mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-08 09:57:15 +03:00
Compare commits
1 Commits
main
...
feature/te
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f2598d0d6 |
@@ -945,7 +945,7 @@ if (WIN32)
|
||||
endif ()
|
||||
endif ()
|
||||
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Orca Slicer is an open source slicer for FDM printers")
|
||||
set (CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/OrcaSlicer/OrcaSlicer")
|
||||
set (CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/OrcaSlicer_3/OrcaSlicer")
|
||||
set (CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
|
||||
set (CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/images\\\\OrcaSlicer.ico")
|
||||
set (CPACK_NSIS_MUI_ICON "${CPACK_PACKAGE_ICON}")
|
||||
|
||||
81
resources/shaders/110/texture_displacement_bump.fs
Normal file
81
resources/shaders/110/texture_displacement_bump.fs
Normal file
@@ -0,0 +1,81 @@
|
||||
#version 110
|
||||
|
||||
// See resources/shaders/140/texture_displacement_bump.fs for full documentation; this is the
|
||||
// GLSL 1.10 compatibility variant (same logic, older syntax).
|
||||
|
||||
#define INTENSITY_CORRECTION 0.6
|
||||
|
||||
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
|
||||
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
|
||||
#define LIGHT_TOP_SHININESS 20.0
|
||||
|
||||
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
|
||||
|
||||
#define INTENSITY_AMBIENT 0.3
|
||||
|
||||
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
uniform vec4 uniform_color;
|
||||
uniform bool volume_mirrored;
|
||||
|
||||
uniform mat4 view_model_matrix;
|
||||
uniform mat3 view_normal_matrix;
|
||||
|
||||
uniform sampler2D height_tex;
|
||||
uniform vec2 height_tex_texel;
|
||||
uniform float depth_mm;
|
||||
uniform float tiling_scale;
|
||||
uniform float rotation_rad;
|
||||
uniform vec2 uv_offset;
|
||||
uniform bool invert;
|
||||
|
||||
varying vec3 clipping_planes_dots;
|
||||
varying vec4 model_pos;
|
||||
varying vec4 world_pos;
|
||||
varying float weight;
|
||||
|
||||
vec2 project_uv(vec3 p, vec3 n)
|
||||
{
|
||||
vec3 an = abs(n);
|
||||
vec2 planar = (an.x >= an.y && an.x >= an.z) ? p.yz : ((an.y >= an.x && an.y >= an.z) ? p.xz : p.xy);
|
||||
planar *= (tiling_scale > 1e-6) ? (1.0 / tiling_scale) : 1.0;
|
||||
float cs = cos(rotation_rad);
|
||||
float sn = sin(rotation_rad);
|
||||
return vec2(planar.x * cs - planar.y * sn, planar.x * sn + planar.y * cs) + uv_offset;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
if (any(lessThan(clipping_planes_dots, ZERO)))
|
||||
discard;
|
||||
|
||||
vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz)));
|
||||
if (volume_mirrored)
|
||||
triangle_normal = -triangle_normal;
|
||||
|
||||
if (weight > 0.0) {
|
||||
vec2 uv = project_uv(model_pos.xyz, triangle_normal);
|
||||
float hL = texture2D(height_tex, uv - vec2(height_tex_texel.x, 0.0)).r;
|
||||
float hR = texture2D(height_tex, uv + vec2(height_tex_texel.x, 0.0)).r;
|
||||
float hD = texture2D(height_tex, uv - vec2(0.0, height_tex_texel.y)).r;
|
||||
float hU = texture2D(height_tex, uv + vec2(0.0, height_tex_texel.y)).r;
|
||||
float sign_mul = invert ? -1.0 : 1.0;
|
||||
vec3 bumped_normal = normalize(triangle_normal + sign_mul * depth_mm * vec3(hL - hR, hD - hU, 0.0));
|
||||
triangle_normal = normalize(mix(triangle_normal, bumped_normal, clamp(weight, 0.0, 1.0)));
|
||||
}
|
||||
|
||||
vec3 eye_normal = normalize(view_normal_matrix * triangle_normal);
|
||||
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
|
||||
|
||||
vec2 intensity = vec2(0.0);
|
||||
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
|
||||
vec3 position = (view_model_matrix * model_pos).xyz;
|
||||
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
|
||||
|
||||
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
|
||||
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
||||
|
||||
gl_FragColor = vec4(vec3(intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
|
||||
}
|
||||
30
resources/shaders/110/texture_displacement_bump.vs
Normal file
30
resources/shaders/110/texture_displacement_bump.vs
Normal file
@@ -0,0 +1,30 @@
|
||||
#version 110
|
||||
|
||||
uniform mat4 view_model_matrix;
|
||||
uniform mat4 projection_matrix;
|
||||
|
||||
uniform mat4 volume_world_matrix;
|
||||
// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane.
|
||||
uniform vec2 z_range;
|
||||
// Clipping plane - general orientation. Used by the SLA gizmo.
|
||||
uniform vec4 clipping_plane;
|
||||
|
||||
attribute vec3 v_position;
|
||||
// Per-vertex paint weight for the currently active texture-displacement layer, 0..1.
|
||||
attribute float v_weight;
|
||||
|
||||
varying vec3 clipping_planes_dots;
|
||||
varying vec4 model_pos;
|
||||
varying vec4 world_pos;
|
||||
varying float weight;
|
||||
|
||||
void main()
|
||||
{
|
||||
model_pos = vec4(v_position, 1.0);
|
||||
world_pos = volume_world_matrix * model_pos;
|
||||
|
||||
gl_Position = projection_matrix * view_model_matrix * model_pos;
|
||||
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
|
||||
|
||||
weight = v_weight;
|
||||
}
|
||||
92
resources/shaders/140/texture_displacement_bump.fs
Normal file
92
resources/shaders/140/texture_displacement_bump.fs
Normal file
@@ -0,0 +1,92 @@
|
||||
#version 140
|
||||
|
||||
// Fast, geometry-free preview of texture displacement: perturbs the *shading* normal from the
|
||||
// height texture's local gradient (a bump map), faded out by the per-vertex paint weight. Used
|
||||
// while the brush is actively dragging (see project plan, "Preview shaders" section); the true,
|
||||
// exact result is what "Bake" produces via libslic3r/TextureDisplacement.cpp on the CPU.
|
||||
//
|
||||
// NOTE: the gradient-to-normal conversion below assumes the two planar-projection axes chosen by
|
||||
// project_uv() are reasonably aligned with the surface here; it is a cheap approximation (no
|
||||
// tangent/bitangent basis is reconstructed on the GPU), acceptable for a live preview but not
|
||||
// intended to be pixel-exact versus the CPU-side bake.
|
||||
|
||||
#define INTENSITY_CORRECTION 0.6
|
||||
|
||||
// normalized values for (-0.6/1.31, 0.6/1.31, 1./1.31)
|
||||
const vec3 LIGHT_TOP_DIR = vec3(-0.4574957, 0.4574957, 0.7624929);
|
||||
#define LIGHT_TOP_DIFFUSE (0.8 * INTENSITY_CORRECTION)
|
||||
#define LIGHT_TOP_SPECULAR (0.125 * INTENSITY_CORRECTION)
|
||||
#define LIGHT_TOP_SHININESS 20.0
|
||||
|
||||
// normalized values for (1./1.43, 0.2/1.43, 1./1.43)
|
||||
const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
||||
#define LIGHT_FRONT_DIFFUSE (0.3 * INTENSITY_CORRECTION)
|
||||
|
||||
#define INTENSITY_AMBIENT 0.3
|
||||
|
||||
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
uniform vec4 uniform_color;
|
||||
uniform bool volume_mirrored;
|
||||
|
||||
uniform mat4 view_model_matrix;
|
||||
uniform mat3 view_normal_matrix;
|
||||
|
||||
uniform sampler2D height_tex;
|
||||
uniform vec2 height_tex_texel; // (1/width, 1/height) of height_tex
|
||||
uniform float depth_mm;
|
||||
uniform float tiling_scale;
|
||||
uniform float rotation_rad;
|
||||
uniform vec2 uv_offset;
|
||||
uniform bool invert;
|
||||
|
||||
in vec3 clipping_planes_dots;
|
||||
in vec4 model_pos;
|
||||
in vec4 world_pos;
|
||||
in float weight;
|
||||
|
||||
out vec4 out_color;
|
||||
|
||||
vec2 project_uv(vec3 p, vec3 n)
|
||||
{
|
||||
vec3 an = abs(n);
|
||||
vec2 planar = (an.x >= an.y && an.x >= an.z) ? p.yz : ((an.y >= an.x && an.y >= an.z) ? p.xz : p.xy);
|
||||
planar *= (tiling_scale > 1e-6) ? (1.0 / tiling_scale) : 1.0;
|
||||
float cs = cos(rotation_rad);
|
||||
float sn = sin(rotation_rad);
|
||||
return vec2(planar.x * cs - planar.y * sn, planar.x * sn + planar.y * cs) + uv_offset;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
if (any(lessThan(clipping_planes_dots, ZERO)))
|
||||
discard;
|
||||
|
||||
vec3 triangle_normal = normalize(cross(dFdx(model_pos.xyz), dFdy(model_pos.xyz)));
|
||||
if (volume_mirrored)
|
||||
triangle_normal = -triangle_normal;
|
||||
|
||||
if (weight > 0.0) {
|
||||
vec2 uv = project_uv(model_pos.xyz, triangle_normal);
|
||||
float hL = texture(height_tex, uv - vec2(height_tex_texel.x, 0.0)).r;
|
||||
float hR = texture(height_tex, uv + vec2(height_tex_texel.x, 0.0)).r;
|
||||
float hD = texture(height_tex, uv - vec2(0.0, height_tex_texel.y)).r;
|
||||
float hU = texture(height_tex, uv + vec2(0.0, height_tex_texel.y)).r;
|
||||
float sign_mul = invert ? -1.0 : 1.0;
|
||||
vec3 bumped_normal = normalize(triangle_normal + sign_mul * depth_mm * vec3(hL - hR, hD - hU, 0.0));
|
||||
triangle_normal = normalize(mix(triangle_normal, bumped_normal, clamp(weight, 0.0, 1.0)));
|
||||
}
|
||||
|
||||
vec3 eye_normal = normalize(view_normal_matrix * triangle_normal);
|
||||
float NdotL = max(dot(eye_normal, LIGHT_TOP_DIR), 0.0);
|
||||
|
||||
vec2 intensity = vec2(0.0);
|
||||
intensity.x = INTENSITY_AMBIENT + NdotL * LIGHT_TOP_DIFFUSE;
|
||||
vec3 position = (view_model_matrix * model_pos).xyz;
|
||||
intensity.y = LIGHT_TOP_SPECULAR * pow(max(dot(-normalize(position), reflect(-LIGHT_TOP_DIR, eye_normal)), 0.0), LIGHT_TOP_SHININESS);
|
||||
|
||||
NdotL = max(dot(eye_normal, LIGHT_FRONT_DIR), 0.0);
|
||||
intensity.x += NdotL * LIGHT_FRONT_DIFFUSE;
|
||||
|
||||
out_color = vec4(vec3(intensity.y) + uniform_color.rgb * intensity.x, uniform_color.a);
|
||||
}
|
||||
32
resources/shaders/140/texture_displacement_bump.vs
Normal file
32
resources/shaders/140/texture_displacement_bump.vs
Normal file
@@ -0,0 +1,32 @@
|
||||
#version 140
|
||||
|
||||
uniform mat4 view_model_matrix;
|
||||
uniform mat4 projection_matrix;
|
||||
|
||||
uniform mat4 volume_world_matrix;
|
||||
// Clipping plane, x = min z, y = max z. Used by the FFF and SLA previews to clip with a top / bottom plane.
|
||||
uniform vec2 z_range;
|
||||
// Clipping plane - general orientation. Used by the SLA gizmo.
|
||||
uniform vec4 clipping_plane;
|
||||
|
||||
in vec3 v_position;
|
||||
// Per-vertex paint weight for the currently active texture-displacement layer, 0..1 (see
|
||||
// TriangleSelectorWeighted... note: Phase 1 stores this as a plain enforced/not-enforced mask,
|
||||
// so this is 0.0 or 1.0 today; a continuous value is a natural later-phase extension).
|
||||
in float v_weight;
|
||||
|
||||
out vec3 clipping_planes_dots;
|
||||
out vec4 model_pos;
|
||||
out vec4 world_pos;
|
||||
out float weight;
|
||||
|
||||
void main()
|
||||
{
|
||||
model_pos = vec4(v_position, 1.0);
|
||||
world_pos = volume_world_matrix * model_pos;
|
||||
|
||||
gl_Position = projection_matrix * view_model_matrix * model_pos;
|
||||
clipping_planes_dots = vec3(dot(world_pos, clipping_plane), world_pos.z - z_range.x, z_range.y - world_pos.z);
|
||||
|
||||
weight = v_weight;
|
||||
}
|
||||
@@ -442,6 +442,8 @@ set(lisbslic3r_sources
|
||||
Tesselate.cpp
|
||||
Tesselate.hpp
|
||||
TextConfiguration.hpp
|
||||
TextureDisplacement.cpp
|
||||
TextureDisplacement.hpp
|
||||
Thread.cpp
|
||||
Thread.hpp
|
||||
Time.cpp
|
||||
|
||||
@@ -1977,6 +1977,11 @@ void ModelVolume::reset_extra_facets()
|
||||
this->seam_facets.reset();
|
||||
this->mmu_segmentation_facets.reset();
|
||||
this->fuzzy_skin_facets.reset();
|
||||
// Texture-displacement paint data has no remap-across-topology-change support yet (see
|
||||
// build_texture_displacement()'s documented limitation), so it must be dropped here rather
|
||||
// than left referring to a mesh that no longer matches it.
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
this->texture_displacement_facet(i).reset();
|
||||
}
|
||||
|
||||
std::optional<TriangleSelector::SavedPainting> ModelVolume::save_painting() const
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "TextConfiguration.hpp"
|
||||
#include "EmbossShape.hpp"
|
||||
#include "TriangleSelector.hpp"
|
||||
#include "TextureDisplacement.hpp"
|
||||
|
||||
//BBS: add bbs 3mf
|
||||
#include "Format/bbs_3mf.hpp"
|
||||
@@ -28,6 +29,7 @@
|
||||
#include "Format/STL.hpp"
|
||||
#include "Format/OBJ.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -878,6 +880,64 @@ public:
|
||||
// List of mesh facets painted for fuzzy skin.
|
||||
FacetsAnnotation fuzzy_skin_facets;
|
||||
|
||||
// One independent paint mask per texture-displacement layer slot (see texture_displacement_layers
|
||||
// below). Unlike the other facets fields above, a triangle may be painted (ENFORCER) in more
|
||||
// than one of these simultaneously -- that overlap is what makes the layers "blend".
|
||||
//
|
||||
// These are 8 plain named fields rather than a std::array<FacetsAnnotation, N>: FacetsAnnotation's
|
||||
// default/copy constructors are private and friended only to ModelVolume, but std::array's own
|
||||
// implicitly-defined default/copy constructors are generated with std::array's access rights,
|
||||
// not ModelVolume's -- so an array of FacetsAnnotation ends up with its default/copy
|
||||
// constructors implicitly deleted regardless of the friend declaration. Use
|
||||
// texture_displacement_facet(slot) below for array-like indexed access.
|
||||
FacetsAnnotation texture_displacement_facets_0;
|
||||
FacetsAnnotation texture_displacement_facets_1;
|
||||
FacetsAnnotation texture_displacement_facets_2;
|
||||
FacetsAnnotation texture_displacement_facets_3;
|
||||
FacetsAnnotation texture_displacement_facets_4;
|
||||
FacetsAnnotation texture_displacement_facets_5;
|
||||
FacetsAnnotation texture_displacement_facets_6;
|
||||
FacetsAnnotation texture_displacement_facets_7;
|
||||
|
||||
FacetsAnnotation& texture_displacement_facet(int slot) {
|
||||
switch (slot) {
|
||||
case 0: return texture_displacement_facets_0;
|
||||
case 1: return texture_displacement_facets_1;
|
||||
case 2: return texture_displacement_facets_2;
|
||||
case 3: return texture_displacement_facets_3;
|
||||
case 4: return texture_displacement_facets_4;
|
||||
case 5: return texture_displacement_facets_5;
|
||||
case 6: return texture_displacement_facets_6;
|
||||
default: assert(slot == 7); return texture_displacement_facets_7;
|
||||
}
|
||||
}
|
||||
const FacetsAnnotation& texture_displacement_facet(int slot) const { return const_cast<ModelVolume*>(this)->texture_displacement_facet(slot); }
|
||||
|
||||
// Small helpers for the constructor asserts below (kept out of line-noise at each call site).
|
||||
bool texture_displacement_facets_ids_valid() const {
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
if (!texture_displacement_facet(i).id().valid() || texture_displacement_facet(i).id() == this->id())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool texture_displacement_facets_ids_invalid() const {
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
if (texture_displacement_facet(i).id().valid())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool texture_displacement_facets_all_empty() const {
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
if (!texture_displacement_facet(i).empty())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Texture assets (height maps) and their projection/displacement parameters. Element order
|
||||
// is not meaningful for baking (layers are applied in TextureDisplacementLayer::slot order,
|
||||
// see build_texture_displacement()); it only reflects UI insertion order.
|
||||
std::vector<TextureDisplacementLayer> texture_displacement_layers;
|
||||
|
||||
// Save painting data before reset_extra_facets() discards it.
|
||||
// Used for replacing mesh without losing painting data.
|
||||
// Only for model parts (not modifiers/connectors).
|
||||
@@ -1007,13 +1067,18 @@ public:
|
||||
this->seam_facets.set_new_unique_id();
|
||||
this->mmu_segmentation_facets.set_new_unique_id();
|
||||
this->fuzzy_skin_facets.set_new_unique_id();
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
this->texture_displacement_facet(i).set_new_unique_id();
|
||||
}
|
||||
|
||||
bool is_fdm_support_painted() const { return !this->supported_facets.empty(); }
|
||||
bool is_seam_painted() const { return !this->seam_facets.empty(); }
|
||||
bool is_mm_painted() const { return !this->mmu_segmentation_facets.empty(); }
|
||||
bool is_fuzzy_skin_painted() const { return !this->fuzzy_skin_facets.empty(); }
|
||||
bool is_any_painted() const { return is_fdm_support_painted() || is_seam_painted() || is_mm_painted() || is_fuzzy_skin_painted(); }
|
||||
bool is_texture_displacement_painted() const { return !this->texture_displacement_facets_all_empty(); }
|
||||
bool is_any_painted() const {
|
||||
return is_fdm_support_painted() || is_seam_painted() || is_mm_painted() || is_fuzzy_skin_painted() || is_texture_displacement_painted();
|
||||
}
|
||||
|
||||
// Orca: Implement prusa's filament shrink compensation approach
|
||||
// Returns 0-based indices of extruders painted by multi-material painting gizmo.
|
||||
@@ -1066,6 +1131,7 @@ private:
|
||||
assert(this->seam_facets.id().valid());
|
||||
assert(this->mmu_segmentation_facets.id().valid());
|
||||
assert(this->fuzzy_skin_facets.id().valid());
|
||||
assert(this->texture_displacement_facets_ids_valid());
|
||||
assert(this->id() != this->config.id());
|
||||
assert(this->id() != this->supported_facets.id());
|
||||
assert(this->id() != this->seam_facets.id());
|
||||
@@ -1082,6 +1148,7 @@ private:
|
||||
assert(this->seam_facets.id().valid());
|
||||
assert(this->mmu_segmentation_facets.id().valid());
|
||||
assert(this->fuzzy_skin_facets.id().valid());
|
||||
assert(this->texture_displacement_facets_ids_valid());
|
||||
assert(this->id() != this->config.id());
|
||||
assert(this->id() != this->supported_facets.id());
|
||||
assert(this->id() != this->seam_facets.id());
|
||||
@@ -1096,6 +1163,7 @@ private:
|
||||
assert(this->seam_facets.id().valid());
|
||||
assert(this->mmu_segmentation_facets.id().valid());
|
||||
assert(this->fuzzy_skin_facets.id().valid());
|
||||
assert(this->texture_displacement_facets_ids_valid());
|
||||
assert(this->id() != this->config.id());
|
||||
assert(this->id() != this->supported_facets.id());
|
||||
assert(this->id() != this->seam_facets.id());
|
||||
@@ -1109,10 +1177,16 @@ private:
|
||||
name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull),
|
||||
config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation),
|
||||
supported_facets(other.supported_facets), seam_facets(other.seam_facets), mmu_segmentation_facets(other.mmu_segmentation_facets),
|
||||
fuzzy_skin_facets(other.fuzzy_skin_facets), cut_info(other.cut_info), text_configuration(other.text_configuration), emboss_shape(other.emboss_shape)
|
||||
fuzzy_skin_facets(other.fuzzy_skin_facets),
|
||||
texture_displacement_facets_0(other.texture_displacement_facets_0), texture_displacement_facets_1(other.texture_displacement_facets_1),
|
||||
texture_displacement_facets_2(other.texture_displacement_facets_2), texture_displacement_facets_3(other.texture_displacement_facets_3),
|
||||
texture_displacement_facets_4(other.texture_displacement_facets_4), texture_displacement_facets_5(other.texture_displacement_facets_5),
|
||||
texture_displacement_facets_6(other.texture_displacement_facets_6), texture_displacement_facets_7(other.texture_displacement_facets_7),
|
||||
texture_displacement_layers(other.texture_displacement_layers),
|
||||
cut_info(other.cut_info), text_configuration(other.text_configuration), emboss_shape(other.emboss_shape)
|
||||
{
|
||||
assert(this->id().valid());
|
||||
assert(this->config.id().valid());
|
||||
assert(this->id().valid());
|
||||
assert(this->config.id().valid());
|
||||
assert(this->supported_facets.id().valid());
|
||||
assert(this->seam_facets.id().valid());
|
||||
assert(this->mmu_segmentation_facets.id().valid());
|
||||
@@ -1162,6 +1236,8 @@ private:
|
||||
assert(this->seam_facets.empty());
|
||||
assert(this->mmu_segmentation_facets.empty());
|
||||
assert(this->fuzzy_skin_facets.empty());
|
||||
assert(this->texture_displacement_facets_all_empty());
|
||||
assert(this->texture_displacement_layers.empty());
|
||||
}
|
||||
|
||||
ModelVolume& operator=(ModelVolume &rhs) = delete;
|
||||
@@ -1169,13 +1245,17 @@ private:
|
||||
friend class cereal::access;
|
||||
friend class UndoRedo::StackImpl;
|
||||
// Used for deserialization, therefore no IDs are allocated.
|
||||
ModelVolume() : ObjectBase(-1), config(-1), supported_facets(-1), seam_facets(-1), mmu_segmentation_facets(-1), fuzzy_skin_facets(-1), object(nullptr) {
|
||||
ModelVolume() : ObjectBase(-1), config(-1), supported_facets(-1), seam_facets(-1), mmu_segmentation_facets(-1), fuzzy_skin_facets(-1),
|
||||
texture_displacement_facets_0(-1), texture_displacement_facets_1(-1), texture_displacement_facets_2(-1), texture_displacement_facets_3(-1),
|
||||
texture_displacement_facets_4(-1), texture_displacement_facets_5(-1), texture_displacement_facets_6(-1), texture_displacement_facets_7(-1),
|
||||
object(nullptr) {
|
||||
assert(this->id().invalid());
|
||||
assert(this->config.id().invalid());
|
||||
assert(this->supported_facets.id().invalid());
|
||||
assert(this->seam_facets.id().invalid());
|
||||
assert(this->mmu_segmentation_facets.id().invalid());
|
||||
assert(this->fuzzy_skin_facets.id().invalid());
|
||||
assert(this->texture_displacement_facets_ids_invalid());
|
||||
}
|
||||
template<class Archive> void load(Archive &ar) {
|
||||
bool has_convex_hull;
|
||||
@@ -1195,6 +1275,13 @@ private:
|
||||
mesh_changed |= t != mmu_segmentation_facets.timestamp();
|
||||
cereal::load_by_value(ar, fuzzy_skin_facets);
|
||||
mesh_changed |= t != fuzzy_skin_facets.timestamp();
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i) {
|
||||
FacetsAnnotation &f = texture_displacement_facet(i);
|
||||
Timestamp tf = f.timestamp();
|
||||
cereal::load_by_value(ar, f);
|
||||
mesh_changed |= tf != f.timestamp();
|
||||
}
|
||||
ar(texture_displacement_layers);
|
||||
cereal::load_by_value(ar, config);
|
||||
cereal::load(ar, text_configuration);
|
||||
cereal::load(ar, emboss_shape);
|
||||
@@ -1216,6 +1303,9 @@ private:
|
||||
cereal::save_by_value(ar, seam_facets);
|
||||
cereal::save_by_value(ar, mmu_segmentation_facets);
|
||||
cereal::save_by_value(ar, fuzzy_skin_facets);
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
cereal::save_by_value(ar, texture_displacement_facet(i));
|
||||
ar(texture_displacement_layers);
|
||||
cereal::save_by_value(ar, config);
|
||||
cereal::save(ar, text_configuration);
|
||||
cereal::save(ar, emboss_shape);
|
||||
|
||||
226
src/libslic3r/TextureDisplacement.cpp
Normal file
226
src/libslic3r/TextureDisplacement.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
#include "TextureDisplacement.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#include "Model.hpp"
|
||||
#include "PNGReadWrite.hpp"
|
||||
#include "TriangleSelector.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
float DecodedHeightTexture::sample(const Vec2f &uv) const
|
||||
{
|
||||
if (empty())
|
||||
return 0.f;
|
||||
|
||||
auto wrap01 = [](float x) {
|
||||
x = std::fmod(x, 1.f);
|
||||
return x < 0.f ? x + 1.f : x;
|
||||
};
|
||||
|
||||
const float fx = wrap01(uv.x()) * float(width);
|
||||
const float fy = wrap01(uv.y()) * float(height);
|
||||
int x0 = int(std::floor(fx)) % width;
|
||||
int y0 = int(std::floor(fy)) % height;
|
||||
if (x0 < 0) x0 += width;
|
||||
if (y0 < 0) y0 += height;
|
||||
const int x1 = (x0 + 1) % width;
|
||||
const int y1 = (y0 + 1) % height;
|
||||
const float tx = fx - std::floor(fx);
|
||||
const float ty = fy - std::floor(fy);
|
||||
|
||||
auto at = [this](int x, int y) { return float(pixels[size_t(y) * size_t(width) + size_t(x)]) / 255.f; };
|
||||
const float top = at(x0, y0) * (1.f - tx) + at(x1, y0) * tx;
|
||||
const float bottom = at(x0, y1) * (1.f - tx) + at(x1, y1) * tx;
|
||||
return top * (1.f - ty) + bottom * ty;
|
||||
}
|
||||
|
||||
DecodedHeightTexture decode_height_texture(const TextureDisplacementLayer &layer)
|
||||
{
|
||||
DecodedHeightTexture result;
|
||||
if (layer.empty())
|
||||
return result;
|
||||
|
||||
const png::ReadBuf rbuf{ layer.image_data->data(), layer.image_data->size() };
|
||||
if (!png::is_png(rbuf))
|
||||
// Only 8-bit grayscale PNG height maps are supported. The GUI is responsible for
|
||||
// converting any imported image (jpg, color png, ...) to that format on import, so this
|
||||
// code never needs a dependency on wxWidgets/libjpeg to decode arbitrary user images.
|
||||
return result;
|
||||
|
||||
png::ImageGreyscale img;
|
||||
if (!png::decode_png(rbuf, img) || img.cols == 0 || img.rows == 0)
|
||||
return result;
|
||||
|
||||
result.width = int(img.cols);
|
||||
result.height = int(img.rows);
|
||||
result.pixels = std::move(img.buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vec2f project_texture_displacement_uv(const Vec3f &position, const Vec3f &normal, const TextureDisplacementLayer &layer)
|
||||
{
|
||||
// Planar-project onto the two axes orthogonal to the dominant component of `normal`. Using a
|
||||
// single projection axis for an entire patch (rather than per-vertex normals) avoids visible
|
||||
// seams where the local normal direction changes. Proper seam-aware UV parametrization is a
|
||||
// later-phase improvement.
|
||||
const Vec3f n = normal.cwiseAbs();
|
||||
Vec2f planar;
|
||||
if (n.x() >= n.y() && n.x() >= n.z())
|
||||
planar = Vec2f(position.y(), position.z());
|
||||
else if (n.y() >= n.x() && n.y() >= n.z())
|
||||
planar = Vec2f(position.x(), position.z());
|
||||
else
|
||||
planar = Vec2f(position.x(), position.y());
|
||||
|
||||
const float scale = (layer.tiling_scale > 1e-6f) ? (1.f / layer.tiling_scale) : 1.f;
|
||||
planar *= scale;
|
||||
|
||||
const float rad = layer.rotation_deg * float(M_PI) / 180.f;
|
||||
const float cs = std::cos(rad);
|
||||
const float sn = std::sin(rad);
|
||||
const Vec2f rotated(planar.x() * cs - planar.y() * sn, planar.x() * sn + planar.y() * cs);
|
||||
|
||||
return rotated + layer.offset;
|
||||
}
|
||||
|
||||
// Area-weighted vertex normals computed from the patch's own (pre-displacement) connectivity.
|
||||
// Since the patch's vertices have not moved yet at the point this is called, these are identical
|
||||
// to the surface normals of the mesh the patch was extracted from.
|
||||
static std::vector<Vec3f> texture_displacement_vertex_normals(const indexed_triangle_set &its)
|
||||
{
|
||||
std::vector<Vec3f> normals(its.vertices.size(), Vec3f::Zero());
|
||||
for (const stl_triangle_vertex_indices &tri : its.indices) {
|
||||
const Vec3f &a = its.vertices[tri[0]];
|
||||
const Vec3f &b = its.vertices[tri[1]];
|
||||
const Vec3f &c = its.vertices[tri[2]];
|
||||
// Cross product magnitude is twice the face area, so this naturally area-weights the
|
||||
// contribution of each incident face to its vertices.
|
||||
const Vec3f area_weighted_normal = (b - a).cross(c - a);
|
||||
normals[tri[0]] += area_weighted_normal;
|
||||
normals[tri[1]] += area_weighted_normal;
|
||||
normals[tri[2]] += area_weighted_normal;
|
||||
}
|
||||
for (Vec3f &n : normals) {
|
||||
const float len = n.norm();
|
||||
n = (len > 1e-8f) ? Vec3f(n / len) : Vec3f::UnitZ();
|
||||
}
|
||||
return normals;
|
||||
}
|
||||
|
||||
indexed_triangle_set build_texture_displacement(const indexed_triangle_set &base_mesh,
|
||||
const std::vector<TextureDisplacementLayer> &layers,
|
||||
const TextureDisplacementFacetsData &facets_data)
|
||||
{
|
||||
const indexed_triangle_set original_mesh = base_mesh;
|
||||
indexed_triangle_set working_mesh = original_mesh;
|
||||
bool mesh_modified = false;
|
||||
|
||||
// Layers behave like stacked image-editor layers: applied in slot order, each one sculpting
|
||||
// the surface left by the layers before it. This is what makes overlapping layers "blend".
|
||||
std::vector<const TextureDisplacementLayer *> ordered_layers;
|
||||
for (const TextureDisplacementLayer &layer : layers)
|
||||
if (!layer.empty() && layer.slot >= 0 && size_t(layer.slot) < TEXTURE_DISPLACEMENT_MAX_LAYERS)
|
||||
ordered_layers.push_back(&layer);
|
||||
std::sort(ordered_layers.begin(), ordered_layers.end(),
|
||||
[](const TextureDisplacementLayer *a, const TextureDisplacementLayer *b) { return a->slot < b->slot; });
|
||||
|
||||
for (const TextureDisplacementLayer *layer : ordered_layers) {
|
||||
const TriangleSelector::TriangleSplittingData &stored_data = facets_data[size_t(layer->slot)];
|
||||
if (stored_data.triangles_to_split.empty())
|
||||
continue;
|
||||
|
||||
const DecodedHeightTexture height = decode_height_texture(*layer);
|
||||
if (height.empty())
|
||||
continue;
|
||||
|
||||
TriangleSelector::TriangleSplittingData data = stored_data;
|
||||
if (mesh_modified) {
|
||||
// The stored paint mask is relative to the volume's original (unbaked) mesh; remap it
|
||||
// onto the working mesh, which earlier layers may have already displaced/subdivided.
|
||||
data = TriangleSelector::remap_painting(original_mesh, data, working_mesh, Transform3d::Identity(),
|
||||
std::optional<std::reference_wrapper<const TriangleSelector::TriangleSplittingData>>{});
|
||||
if (data.bitstream.empty())
|
||||
continue;
|
||||
}
|
||||
|
||||
const TriangleMesh selector_mesh(working_mesh);
|
||||
TriangleSelector selector(selector_mesh);
|
||||
selector.deserialize(data, false);
|
||||
|
||||
const indexed_triangle_set patch = selector.get_facets_strict(EnforcerBlockerType::ENFORCER);
|
||||
if (patch.indices.empty())
|
||||
continue;
|
||||
// get_facets_strict() returns the *entire* mesh's vertex array regardless of which state
|
||||
// was asked for (only the returned triangle indices are filtered by state) -- so `patch`
|
||||
// and `rest` share the exact same vertex indexing. That is what lets the weld below be a
|
||||
// plain index check instead of a position-based lookup.
|
||||
indexed_triangle_set rest = selector.get_facets_strict(EnforcerBlockerType::NONE);
|
||||
assert(rest.vertices.size() == patch.vertices.size());
|
||||
|
||||
// A vertex that is also used by at least one *unpainted* triangle is a boundary vertex:
|
||||
// its final position is ambiguous (it belongs to both the painted and untouched surface),
|
||||
// so it must never be displaced -- otherwise the baked patch would tear away from the
|
||||
// rest of the mesh. Only vertices used exclusively by painted triangles ("interior" to the
|
||||
// patch) are eligible for displacement. This is what keeps the bake seamless without any
|
||||
// remeshing/hole-filling at the boundary.
|
||||
std::vector<bool> is_boundary_vertex(rest.vertices.size(), false);
|
||||
for (const stl_triangle_vertex_indices &tri : rest.indices)
|
||||
for (int i = 0; i < 3; ++i)
|
||||
is_boundary_vertex[tri[i]] = true;
|
||||
|
||||
const std::vector<Vec3f> vertex_normals = texture_displacement_vertex_normals(patch);
|
||||
|
||||
Vec3f average_normal = Vec3f::Zero();
|
||||
for (const stl_triangle_vertex_indices &tri : patch.indices)
|
||||
for (int i = 0; i < 3; ++i)
|
||||
average_normal += vertex_normals[tri[i]];
|
||||
average_normal = (average_normal.norm() > 1e-8f) ? Vec3f(average_normal.normalized()) : Vec3f::UnitZ();
|
||||
|
||||
const float sign = layer->invert ? -1.f : 1.f;
|
||||
std::vector<int> interior_vertex_remap(rest.vertices.size(), -1);
|
||||
indexed_triangle_set working_mesh_next = std::move(rest);
|
||||
for (const stl_triangle_vertex_indices &tri : patch.indices) {
|
||||
stl_triangle_vertex_indices final_tri;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
const int vi = tri[i];
|
||||
if (is_boundary_vertex[vi]) {
|
||||
// Shared with the untouched surface: reuse the existing, undisplaced vertex.
|
||||
final_tri[i] = vi;
|
||||
continue;
|
||||
}
|
||||
if (interior_vertex_remap[vi] < 0) {
|
||||
const Vec2f uv = project_texture_displacement_uv(patch.vertices[vi], average_normal, *layer);
|
||||
const float h = height.sample(uv);
|
||||
const Vec3f displaced = patch.vertices[vi] + vertex_normals[vi] * (h * layer->depth_mm * sign);
|
||||
interior_vertex_remap[vi] = int(working_mesh_next.vertices.size());
|
||||
working_mesh_next.vertices.push_back(displaced);
|
||||
}
|
||||
final_tri[i] = interior_vertex_remap[vi];
|
||||
}
|
||||
working_mesh_next.indices.push_back(final_tri);
|
||||
}
|
||||
|
||||
working_mesh = std::move(working_mesh_next);
|
||||
mesh_modified = true;
|
||||
}
|
||||
|
||||
if (mesh_modified)
|
||||
its_compactify_vertices(working_mesh);
|
||||
|
||||
return working_mesh;
|
||||
}
|
||||
|
||||
indexed_triangle_set build_texture_displacement(const ModelVolume &volume)
|
||||
{
|
||||
TextureDisplacementFacetsData facets_data;
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
facets_data[size_t(i)] = volume.texture_displacement_facet(i).get_data();
|
||||
|
||||
return build_texture_displacement(volume.mesh().its, volume.texture_displacement_layers, facets_data);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
120
src/libslic3r/TextureDisplacement.hpp
Normal file
120
src/libslic3r/TextureDisplacement.hpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#ifndef slic3r_TextureDisplacement_hpp_
|
||||
#define slic3r_TextureDisplacement_hpp_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/types/string.hpp>
|
||||
#include <cereal/types/vector.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "Point.hpp"
|
||||
#include "TriangleMesh.hpp"
|
||||
#include "TriangleSelector.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class ModelVolume;
|
||||
|
||||
// Maximum number of simultaneous texture-displacement layers a single ModelVolume can hold.
|
||||
// Each layer owns its own paint mask (ModelVolume::texture_displacement_facet(slot)), so this
|
||||
// is also the number of independent EnforcerBlockerType selectors kept per volume.
|
||||
static constexpr size_t TEXTURE_DISPLACEMENT_MAX_LAYERS = 8;
|
||||
|
||||
// One texture asset plus its projection/displacement parameters. Several layers may be painted
|
||||
// onto overlapping areas of the same volume: they are applied in slot order (like layers in an
|
||||
// image editor), each one displacing the surface that resulted from the layers before it. This
|
||||
// is what "layered/blended" texture displacement means in this feature.
|
||||
struct TextureDisplacementLayer
|
||||
{
|
||||
// Index into ModelVolume::texture_displacement_facets, assigned once when the layer is
|
||||
// created. Not reused for the lifetime of the ModelVolume, so a deleted layer's slot simply
|
||||
// becomes unused rather than being handed to a different layer.
|
||||
int slot = -1;
|
||||
|
||||
std::string name;
|
||||
// Path on the local filesystem the image was loaded from (informational; may be stale or
|
||||
// empty, e.g. after loading a .3mf on a different machine).
|
||||
std::string path;
|
||||
// Path inside the .3mf archive once saved (empty until the project is saved once).
|
||||
std::string path_in_3mf;
|
||||
// Raw encoded image bytes. Only 8-bit grayscale PNG is understood by decode_height_texture()
|
||||
// (libslic3r has no GUI image toolkit available); the GUI converts any imported image to that
|
||||
// format before storing it here, so the baking code never needs to depend on wxWidgets.
|
||||
std::shared_ptr<std::vector<unsigned char>> image_data;
|
||||
|
||||
float depth_mm = 0.4f; // maximum displacement along the surface normal, in mm
|
||||
float tiling_scale = 10.f; // size of one texture tile, in mm
|
||||
float rotation_deg = 0.f;
|
||||
Vec2f offset = Vec2f::Zero();
|
||||
bool invert = false;
|
||||
|
||||
bool empty() const { return !image_data || image_data->empty(); }
|
||||
|
||||
template<class Archive> void save(Archive &ar) const
|
||||
{
|
||||
std::string blob = image_data ? std::string(image_data->begin(), image_data->end()) : std::string();
|
||||
ar(slot, name, path, path_in_3mf, blob, depth_mm, tiling_scale, rotation_deg, offset, invert);
|
||||
}
|
||||
template<class Archive> void load(Archive &ar)
|
||||
{
|
||||
std::string blob;
|
||||
ar(slot, name, path, path_in_3mf, blob, depth_mm, tiling_scale, rotation_deg, offset, invert);
|
||||
image_data = blob.empty() ? nullptr : std::make_shared<std::vector<unsigned char>>(blob.begin(), blob.end());
|
||||
}
|
||||
};
|
||||
|
||||
// Decoded 8-bit grayscale height sample, independent of any GUI/OpenGL texture object so it can
|
||||
// be evaluated from a background bake Job as well as from GUI-side preview code.
|
||||
struct DecodedHeightTexture
|
||||
{
|
||||
std::vector<uint8_t> pixels; // row-major, top-to-bottom, one byte per pixel
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
bool empty() const { return width <= 0 || height <= 0 || pixels.empty(); }
|
||||
// Bilinearly sampled height in [0, 1] at a tiling (wrapping) normalized uv coordinate.
|
||||
float sample(const Vec2f &uv) const;
|
||||
};
|
||||
|
||||
// Decode a layer's raw image bytes into sampleable grayscale height data. Returns an empty
|
||||
// DecodedHeightTexture if image_data is empty or is not an 8-bit grayscale PNG.
|
||||
DecodedHeightTexture decode_height_texture(const TextureDisplacementLayer &layer);
|
||||
|
||||
// Project a mesh-local position onto a layer's height texture, honouring its tiling scale,
|
||||
// rotation and offset. Uses a simple dominant-axis planar projection of the given normal: proper
|
||||
// seam-aware UV parametrization is a later-phase improvement (see project plan).
|
||||
Vec2f project_texture_displacement_uv(const Vec3f &position, const Vec3f &normal, const TextureDisplacementLayer &layer);
|
||||
|
||||
// One paint mask (as stored by ModelVolume::texture_displacement_facets) per possible layer slot.
|
||||
using TextureDisplacementFacetsData = std::array<TriangleSelector::TriangleSplittingData, TEXTURE_DISPLACEMENT_MAX_LAYERS>;
|
||||
|
||||
// Bake all painted texture-displacement layers into `base_mesh`'s geometry, restricted to the
|
||||
// painted area(s) only (the rest of the mesh is left untouched). Layers are applied in slot
|
||||
// order, each measuring its displacement from the surface left by the previous one. Returns the
|
||||
// mesh unchanged if nothing is painted or no layer has a usable texture.
|
||||
//
|
||||
// Takes plain copied data rather than a ModelVolume reference so it is safe to call from a
|
||||
// background thread (e.g. a bake Job's process() method) on a snapshot captured on the main
|
||||
// thread, without touching the live Model concurrently with the UI.
|
||||
//
|
||||
// Known Phase 1-3 limitation: this does not attempt to remap texture-displacement paint data
|
||||
// across topology-changing operations performed outside this gizmo (e.g. ModelObject::split(),
|
||||
// mesh-boolean ops) the way TriangleSelector::remap_painting() does for the other paint channels.
|
||||
// Such operations will silently drop any unbaked texture-displacement paint on the affected
|
||||
// volume. This is an explicit extension point for a later phase, not an oversight.
|
||||
indexed_triangle_set build_texture_displacement(const indexed_triangle_set &base_mesh,
|
||||
const std::vector<TextureDisplacementLayer> &layers,
|
||||
const TextureDisplacementFacetsData &facets_data);
|
||||
|
||||
// Convenience overload for main-thread callers: extracts the mesh/layers/paint data from `volume`
|
||||
// and forwards to the overload above.
|
||||
indexed_triangle_set build_texture_displacement(const ModelVolume &volume);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // slic3r_TextureDisplacement_hpp_
|
||||
@@ -172,6 +172,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/Gizmos/GLGizmosManager.hpp
|
||||
GUI/Gizmos/GLGizmoSVG.cpp
|
||||
GUI/Gizmos/GLGizmoSVG.hpp
|
||||
GUI/Gizmos/GLGizmoTextureDisplacement.cpp
|
||||
GUI/Gizmos/GLGizmoTextureDisplacement.hpp
|
||||
GUI/Gizmos/GLGizmoUtils.cpp
|
||||
GUI/Gizmos/GLGizmoUtils.hpp
|
||||
#GUI/Gizmos/GLGizmoText.cpp
|
||||
@@ -297,6 +299,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/Jobs/SLAImportDialog.hpp
|
||||
GUI/Jobs/SLAImportJob.cpp
|
||||
GUI/Jobs/SLAImportJob.hpp
|
||||
GUI/Jobs/TextureDisplacementBakeJob.cpp
|
||||
GUI/Jobs/TextureDisplacementBakeJob.hpp
|
||||
GUI/Jobs/ThreadSafeQueue.hpp
|
||||
GUI/Jobs/UpgradeNetworkJob.cpp
|
||||
GUI/Jobs/UpgradeNetworkJob.hpp
|
||||
|
||||
@@ -100,6 +100,8 @@ std::pair<bool, std::string> GLShadersManager::init()
|
||||
valid &= append_shader("mm_gouraud", { prefix + "mm_gouraud.vs", prefix + "mm_gouraud.fs" }, { "FLIP_TRIANGLE_NORMALS"sv });
|
||||
else
|
||||
valid &= append_shader("mm_gouraud", { prefix + "mm_gouraud.vs", prefix + "mm_gouraud.fs" });
|
||||
// Fast bump-map preview for the texture displacement gizmo (see libslic3r/TextureDisplacement.hpp).
|
||||
valid &= append_shader("texture_displacement_bump", { prefix + "texture_displacement_bump.vs", prefix + "texture_displacement_bump.fs" });
|
||||
|
||||
return { valid, error };
|
||||
}
|
||||
|
||||
@@ -27,7 +27,8 @@ enum class PainterGizmoType {
|
||||
FDM_SUPPORTS,
|
||||
SEAM,
|
||||
MM_SEGMENTATION,
|
||||
FUZZY_SKIN
|
||||
FUZZY_SKIN,
|
||||
TEXTURE_DISPLACEMENT
|
||||
};
|
||||
|
||||
class TriangleSelectorGUI : public TriangleSelector {
|
||||
|
||||
362
src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp
Normal file
362
src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
#include "GLGizmoTextureDisplacement.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/PNGReadWrite.hpp"
|
||||
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/Jobs/TextureDisplacementBakeJob.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "GLGizmoUtils.hpp"
|
||||
|
||||
#include <glad/gl.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
GLGizmoTextureDisplacement::GLGizmoTextureDisplacement(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoPainterBase(parent, icon_filename, sprite_id)
|
||||
{
|
||||
}
|
||||
|
||||
bool GLGizmoTextureDisplacement::on_init()
|
||||
{
|
||||
m_desc["cursor_size"] = _L("Brush size");
|
||||
m_desc["circle"] = _L("Circle");
|
||||
m_desc["sphere"] = _L("Sphere");
|
||||
m_desc["add_texture"] = _L("Add texture...");
|
||||
m_desc["remove_layer"] = _L("Remove");
|
||||
m_desc["bake"] = _L("Bake");
|
||||
m_desc["remove_all"] = _L("Erase all");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GLGizmoTextureDisplacement::on_get_name() const
|
||||
{
|
||||
return _u8L("Texture displacement");
|
||||
}
|
||||
|
||||
void GLGizmoTextureDisplacement::on_shutdown()
|
||||
{
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
}
|
||||
|
||||
PainterGizmoType GLGizmoTextureDisplacement::get_painter_type() const
|
||||
{
|
||||
return PainterGizmoType::TEXTURE_DISPLACEMENT;
|
||||
}
|
||||
|
||||
wxString GLGizmoTextureDisplacement::handle_snapshot_action_name(bool shift_down, GLGizmoPainterBase::Button button_down) const
|
||||
{
|
||||
return shift_down ? _L("Erase texture displacement paint") : _L("Paint texture displacement");
|
||||
}
|
||||
|
||||
void GLGizmoTextureDisplacement::render_painter_gizmo()
|
||||
{
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
// Phase 1 reuses the standard paint-mask overlay (as every other paint gizmo does) to show
|
||||
// which area of the active layer is painted. A dedicated bump-map preview shader
|
||||
// (resources/shaders/*/texture_displacement_bump.*) is registered and ready to use, but
|
||||
// wiring it into this render path is deferred to a later phase -- see the project plan.
|
||||
// "Bake" already shows the true, real-geometry result, which is the most important preview.
|
||||
render_triangles(selection);
|
||||
m_c->object_clipper()->render_cut();
|
||||
m_c->instances_hider()->render_cut();
|
||||
render_cursor();
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
ModelVolume* GLGizmoTextureDisplacement::texture_volume()
|
||||
{
|
||||
ModelObject *mo = m_c->selection_info()->model_object();
|
||||
if (!mo)
|
||||
return nullptr;
|
||||
for (ModelVolume *mv : mo->volumes)
|
||||
if (mv->is_model_part())
|
||||
return mv;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ModelVolume* GLGizmoTextureDisplacement::texture_volume() const
|
||||
{
|
||||
return const_cast<GLGizmoTextureDisplacement *>(this)->texture_volume();
|
||||
}
|
||||
|
||||
void GLGizmoTextureDisplacement::update_model_object()
|
||||
{
|
||||
bool updated = false;
|
||||
ModelObject *mo = m_c->selection_info()->model_object();
|
||||
int idx = -1;
|
||||
for (ModelVolume *mv : mo->volumes) {
|
||||
if (!mv->is_model_part())
|
||||
continue;
|
||||
++idx;
|
||||
updated |= mv->texture_displacement_facet(m_active_layer_slot).set(*m_triangle_selectors[idx]);
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
const ModelObjectPtrs &mos = wxGetApp().model().objects;
|
||||
wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin());
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoTextureDisplacement::update_from_model_object(bool first_update)
|
||||
{
|
||||
wxBusyCursor wait;
|
||||
|
||||
const ModelObject *mo = m_c->selection_info()->model_object();
|
||||
m_triangle_selectors.clear();
|
||||
|
||||
std::vector<ColorRGBA> ebt_colors;
|
||||
ebt_colors.push_back(GLVolume::NEUTRAL_COLOR);
|
||||
ebt_colors.push_back(TriangleSelectorGUI::enforcers_color);
|
||||
ebt_colors.push_back(TriangleSelectorGUI::blockers_color);
|
||||
for (const ModelVolume *mv : mo->volumes) {
|
||||
if (!mv->is_model_part())
|
||||
continue;
|
||||
|
||||
const TriangleMesh *mesh = &mv->mesh();
|
||||
m_triangle_selectors.emplace_back(std::make_unique<TriangleSelectorPatch>(*mesh, ebt_colors));
|
||||
m_triangle_selectors.back()->deserialize(mv->texture_displacement_facet(m_active_layer_slot).get_data(), false);
|
||||
m_triangle_selectors.back()->request_update_render_data();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoTextureDisplacement::set_active_layer(int slot)
|
||||
{
|
||||
if (slot == m_active_layer_slot)
|
||||
return;
|
||||
// Flush edits made while the previous layer was active before switching what the selectors
|
||||
// reflect -- otherwise they would be silently lost.
|
||||
update_model_object();
|
||||
m_active_layer_slot = slot;
|
||||
update_from_model_object(false);
|
||||
}
|
||||
|
||||
void GLGizmoTextureDisplacement::add_texture_layer()
|
||||
{
|
||||
ModelVolume *mv = texture_volume();
|
||||
if (!mv)
|
||||
return;
|
||||
|
||||
std::array<bool, TEXTURE_DISPLACEMENT_MAX_LAYERS> used{};
|
||||
for (const TextureDisplacementLayer &l : mv->texture_displacement_layers)
|
||||
if (l.slot >= 0 && size_t(l.slot) < used.size())
|
||||
used[size_t(l.slot)] = true;
|
||||
int free_slot = -1;
|
||||
for (size_t i = 0; i < used.size(); ++i)
|
||||
if (!used[i]) { free_slot = int(i); break; }
|
||||
if (free_slot < 0) {
|
||||
show_error(nullptr, _u8L("Maximum number of texture displacement layers reached."));
|
||||
return;
|
||||
}
|
||||
|
||||
const wxString wildcard = "Images (*.png;*.jpg;*.jpeg;*.bmp)|*.png;*.jpg;*.jpeg;*.bmp";
|
||||
wxFileDialog dialog(nullptr, _L("Choose a texture image (height map)"), wxEmptyString, wxEmptyString, wildcard,
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
if (dialog.ShowModal() != wxID_OK)
|
||||
return;
|
||||
|
||||
const std::string path = into_u8(dialog.GetPath());
|
||||
|
||||
wxImage image;
|
||||
if (!image.LoadFile(dialog.GetPath()) || !image.IsOk()) {
|
||||
show_error(nullptr, _u8L("Could not load the selected image."));
|
||||
return;
|
||||
}
|
||||
|
||||
// libslic3r's PNG decoder (used by the baking code, which has no wxWidgets dependency) only
|
||||
// understands true 8-bit grayscale PNG. Convert and re-encode through Slic3r's own PNG writer
|
||||
// here rather than relying on wxImage's PNG encoder to pick a compatible color type.
|
||||
const wxImage gray = image.ConvertToGreyscale();
|
||||
const int w = gray.GetWidth();
|
||||
const int h = gray.GetHeight();
|
||||
if (w <= 0 || h <= 0) {
|
||||
show_error(nullptr, _u8L("The selected image is empty."));
|
||||
return;
|
||||
}
|
||||
std::vector<uint8_t> gray_pixels(size_t(w) * size_t(h));
|
||||
const unsigned char *rgb = gray.GetData();
|
||||
for (size_t i = 0; i < gray_pixels.size(); ++i)
|
||||
gray_pixels[i] = rgb[i * 3];
|
||||
|
||||
const boost::filesystem::path tmp_path = boost::filesystem::temp_directory_path()
|
||||
/ boost::filesystem::unique_path("orca_texdisp_%%%%%%%%.png");
|
||||
if (!Slic3r::png::write_gray_to_file(tmp_path.string(), size_t(w), size_t(h), gray_pixels)) {
|
||||
show_error(nullptr, _u8L("Failed to prepare the texture for use."));
|
||||
return;
|
||||
}
|
||||
std::vector<unsigned char> bytes;
|
||||
{
|
||||
std::ifstream ifs(tmp_path.string(), std::ios::binary);
|
||||
bytes.assign(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
|
||||
}
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove(tmp_path, ec);
|
||||
|
||||
if (bytes.empty()) {
|
||||
show_error(nullptr, _u8L("Failed to prepare the texture for use."));
|
||||
return;
|
||||
}
|
||||
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Add texture displacement layer"), UndoRedo::SnapshotType::GizmoAction);
|
||||
|
||||
TextureDisplacementLayer layer;
|
||||
layer.slot = free_slot;
|
||||
layer.name = boost::filesystem::path(path).filename().string();
|
||||
layer.path = path;
|
||||
layer.image_data = std::make_shared<std::vector<unsigned char>>(std::move(bytes));
|
||||
mv->texture_displacement_layers.push_back(std::move(layer));
|
||||
|
||||
set_active_layer(free_slot);
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
|
||||
void GLGizmoTextureDisplacement::remove_texture_layer(int slot)
|
||||
{
|
||||
ModelVolume *mv = texture_volume();
|
||||
if (!mv)
|
||||
return;
|
||||
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Remove texture displacement layer"), UndoRedo::SnapshotType::GizmoAction);
|
||||
|
||||
auto &layers = mv->texture_displacement_layers;
|
||||
layers.erase(std::remove_if(layers.begin(), layers.end(),
|
||||
[slot](const TextureDisplacementLayer &l) { return l.slot == slot; }),
|
||||
layers.end());
|
||||
if (slot >= 0 && slot < int(TEXTURE_DISPLACEMENT_MAX_LAYERS))
|
||||
mv->texture_displacement_facet(slot).reset();
|
||||
|
||||
if (m_active_layer_slot == slot)
|
||||
update_from_model_object(false);
|
||||
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
|
||||
void GLGizmoTextureDisplacement::bake()
|
||||
{
|
||||
ModelVolume *mv = texture_volume();
|
||||
if (!mv || m_bake_in_progress)
|
||||
return;
|
||||
|
||||
// Make sure the currently active layer's in-progress edits are flushed into the model before
|
||||
// baking, otherwise the most recent, not-yet-committed strokes would be silently skipped.
|
||||
update_model_object();
|
||||
|
||||
if (!mv->is_texture_displacement_painted()) {
|
||||
show_error(nullptr, _u8L("Nothing is painted, there is nothing to bake."));
|
||||
return;
|
||||
}
|
||||
|
||||
m_bake_in_progress = true;
|
||||
queue_texture_displacement_bake(*mv, [this]() { m_bake_in_progress = false; });
|
||||
}
|
||||
|
||||
void GLGizmoTextureDisplacement::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
ModelObject *mo = m_c->selection_info()->model_object();
|
||||
if (!mo)
|
||||
return;
|
||||
ModelVolume *mv = texture_volume();
|
||||
|
||||
const float approx_height = m_imgui->scaled(24.f);
|
||||
y = std::min(y, bottom_limit - approx_height);
|
||||
GizmoImguiSetNextWIndowPos(x, y, ImGuiCond_Always, 1.0f, 0.0f);
|
||||
|
||||
ImGuiWrapper::push_toolbar_style(m_parent.get_scale());
|
||||
GizmoImguiBegin(get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar);
|
||||
|
||||
m_imgui->text(m_desc.at("cursor_size"));
|
||||
ImGui::SameLine();
|
||||
ImGui::PushItemWidth(m_imgui->scaled(7.f));
|
||||
m_imgui->slider_float("##cursor_radius", &m_cursor_radius, CursorRadiusMin, CursorRadiusMax, "%.2f");
|
||||
|
||||
bool is_circle = m_cursor_type == TriangleSelector::CursorType::CIRCLE;
|
||||
if (ImGui::RadioButton(m_desc.at("circle").ToUTF8().data(), is_circle))
|
||||
m_cursor_type = TriangleSelector::CursorType::CIRCLE;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton(m_desc.at("sphere").ToUTF8().data(), !is_circle))
|
||||
m_cursor_type = TriangleSelector::CursorType::SPHERE;
|
||||
|
||||
ImGui::Separator();
|
||||
m_imgui->text(_L("Texture layers"));
|
||||
|
||||
if (mv != nullptr) {
|
||||
std::vector<TextureDisplacementLayer *> ordered;
|
||||
for (TextureDisplacementLayer &l : mv->texture_displacement_layers)
|
||||
ordered.push_back(&l);
|
||||
std::sort(ordered.begin(), ordered.end(), [](const auto *a, const auto *b) { return a->slot < b->slot; });
|
||||
|
||||
for (TextureDisplacementLayer *layer : ordered) {
|
||||
ImGui::PushID(layer->slot);
|
||||
const bool is_active = layer->slot == m_active_layer_slot;
|
||||
if (ImGui::RadioButton("##active", is_active))
|
||||
set_active_layer(layer->slot);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%s", layer->name.empty() ? "texture" : layer->name.c_str());
|
||||
ImGui::SameLine();
|
||||
if (m_imgui->button(m_desc.at("remove_layer")))
|
||||
remove_texture_layer(layer->slot);
|
||||
|
||||
ImGui::PushItemWidth(m_imgui->scaled(7.f));
|
||||
m_imgui->slider_float(_u8L("Depth (mm)"), &layer->depth_mm, 0.02f, 5.f, "%.2f");
|
||||
m_imgui->slider_float(_u8L("Tile size (mm)"), &layer->tiling_scale, 0.5f, 100.f, "%.1f");
|
||||
m_imgui->slider_float(_u8L("Rotation"), &layer->rotation_deg, 0.f, 360.f, "%.0f");
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Checkbox(_u8L("Invert").c_str(), &layer->invert);
|
||||
ImGui::PopID();
|
||||
ImGui::Separator();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_imgui->button(m_desc.at("add_texture")))
|
||||
add_texture_layer();
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
m_imgui->disabled_begin(mv == nullptr || !mv->is_texture_displacement_painted());
|
||||
if (m_imgui->button(m_desc.at("remove_all"))) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _u8L("Reset texture displacement selection"), UndoRedo::SnapshotType::GizmoAction);
|
||||
int idx = -1;
|
||||
for (ModelVolume *v : mo->volumes)
|
||||
if (v->is_model_part()) {
|
||||
++idx;
|
||||
m_triangle_selectors[idx]->reset();
|
||||
m_triangle_selectors[idx]->request_update_render_data();
|
||||
}
|
||||
update_model_object();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::SameLine();
|
||||
m_imgui->disabled_begin(m_bake_in_progress || mv == nullptr || !mv->is_texture_displacement_painted());
|
||||
if (m_imgui->button(m_bake_in_progress ? _L("Baking...") : m_desc.at("bake")))
|
||||
bake();
|
||||
m_imgui->disabled_end();
|
||||
|
||||
ImGui::Separator();
|
||||
if (m_imgui->button(_L("Done")))
|
||||
m_parent.reset_all_gizmos();
|
||||
|
||||
GizmoImguiEnd();
|
||||
ImGuiWrapper::pop_toolbar_style();
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
70
src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp
Normal file
70
src/slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef slic3r_GLGizmoTextureDisplacement_hpp_
|
||||
#define slic3r_GLGizmoTextureDisplacement_hpp_
|
||||
|
||||
#include "GLGizmoPainterBase.hpp"
|
||||
#include "libslic3r/TextureDisplacement.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
// Paint-style gizmo that assigns one or more texture-displacement "layers" (see
|
||||
// libslic3r/TextureDisplacement.hpp) to painted areas of a model, and can bake the result into
|
||||
// real mesh geometry. See the project plan for the overall architecture; in short:
|
||||
// - each layer owns its own independent paint mask (ModelVolume::texture_displacement_facets),
|
||||
// reusing the same TriangleSelector/FacetsAnnotation machinery as every other paint gizmo --
|
||||
// only one layer is "active" (paintable) at a time, selected in the panel below;
|
||||
// - "Bake" runs build_texture_displacement() in a background job and commits the result exactly
|
||||
// like the Emboss/SVG "project on surface" gizmo does.
|
||||
class GLGizmoTextureDisplacement : public GLGizmoPainterBase
|
||||
{
|
||||
public:
|
||||
GLGizmoTextureDisplacement(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
|
||||
void render_painter_gizmo() override;
|
||||
|
||||
protected:
|
||||
void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
std::string on_get_name() const override;
|
||||
|
||||
wxString handle_snapshot_action_name(bool shift_down, Button button_down) const override;
|
||||
|
||||
std::string get_gizmo_entering_text() const override { return _u8L("Entering Texture displacement painting"); }
|
||||
std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Texture displacement painting"); }
|
||||
std::string get_action_snapshot_name() const override { return _u8L("Texture displacement editing"); }
|
||||
|
||||
EnforcerBlockerType get_left_button_state_type() const override { return EnforcerBlockerType::ENFORCER; }
|
||||
EnforcerBlockerType get_right_button_state_type() const override { return EnforcerBlockerType::NONE; }
|
||||
|
||||
private:
|
||||
bool on_init() override;
|
||||
void update_model_object() override;
|
||||
void update_from_model_object(bool first_update) override;
|
||||
void on_opening() override {}
|
||||
void on_shutdown() override;
|
||||
PainterGizmoType get_painter_type() const override;
|
||||
|
||||
// Phase 1 restricts the texture layer list to the first model-part volume of the current
|
||||
// object (the common single-volume case); multi-part objects only get texture layers on
|
||||
// their first part until a later phase. Returns nullptr if there is no model part.
|
||||
ModelVolume* texture_volume();
|
||||
const ModelVolume* texture_volume() const;
|
||||
|
||||
void add_texture_layer();
|
||||
void remove_texture_layer(int slot);
|
||||
void set_active_layer(int slot); // flushes the previous layer's edits, then reloads selectors
|
||||
void bake();
|
||||
|
||||
// Which of the up to TEXTURE_DISPLACEMENT_MAX_LAYERS paint masks the brush currently writes
|
||||
// into. Always a valid slot index (0 by default) so the base class's per-volume selector
|
||||
// machinery always has something to work with, even before any texture has been added --
|
||||
// painting into a slot with no texture assigned is harmless, it just has no visible/bake
|
||||
// effect until a texture is added to that slot.
|
||||
int m_active_layer_slot = 0;
|
||||
bool m_bake_in_progress = false;
|
||||
|
||||
std::map<std::string, wxString> m_desc;
|
||||
};
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
#endif // slic3r_GLGizmoTextureDisplacement_hpp_
|
||||
@@ -22,6 +22,7 @@
|
||||
//#include "slic3r/GUI/Gizmos/GLGizmoHollow.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoSeam.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoTextureDisplacement.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoSimplify.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoEmboss.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoSVG.hpp"
|
||||
@@ -164,6 +165,9 @@ void GLGizmosManager::switch_gizmos_icon_filename()
|
||||
case(EType::FuzzySkin):
|
||||
gizmo->set_icon_filename(m_is_dark ? "toolbar_fuzzy_skin_paint_dark.svg" : "toolbar_fuzzy_skin_paint.svg");
|
||||
break;
|
||||
case(EType::TextureDisplacement):
|
||||
gizmo->set_icon_filename(m_is_dark ? "toolbar_fuzzy_skin_paint_dark.svg" : "toolbar_fuzzy_skin_paint.svg");
|
||||
break;
|
||||
case(EType::MeshBoolean):
|
||||
gizmo->set_icon_filename(m_is_dark ? "toolbar_meshboolean_dark.svg" : "toolbar_meshboolean.svg");
|
||||
break;
|
||||
@@ -213,6 +217,9 @@ bool GLGizmosManager::init()
|
||||
m_gizmos.emplace_back(new GLGizmoSeam(m_parent, m_is_dark ? "toolbar_seam_dark.svg" : "toolbar_seam.svg", EType::Seam));
|
||||
m_gizmos.emplace_back(new GLGizmoFuzzySkin(m_parent, m_is_dark ? "toolbar_fuzzy_skin_paint_dark.svg" : "toolbar_fuzzy_skin_paint.svg", EType::FuzzySkin));
|
||||
m_gizmos.emplace_back(new GLGizmoMmuSegmentation(m_parent, m_is_dark ? "mmu_segmentation_dark.svg" : "mmu_segmentation.svg", EType::MmSegmentation));
|
||||
// TODO: placeholder icon reused from the fuzzy-skin gizmo; swap in a dedicated
|
||||
// toolbar_texture_displacement(_dark).svg once one exists.
|
||||
m_gizmos.emplace_back(new GLGizmoTextureDisplacement(m_parent, m_is_dark ? "toolbar_fuzzy_skin_paint_dark.svg" : "toolbar_fuzzy_skin_paint.svg", EType::TextureDisplacement));
|
||||
m_gizmos.emplace_back(new GLGizmoEmboss(m_parent, m_is_dark ? "toolbar_text_dark.svg" : "toolbar_text.svg", EType::Emboss));
|
||||
m_gizmos.emplace_back(new GLGizmoSVG(m_parent));
|
||||
m_gizmos.emplace_back(new GLGizmoMeasure(m_parent, m_is_dark ? "toolbar_measure_dark.svg" : "toolbar_measure.svg", EType::Measure));
|
||||
@@ -524,6 +531,8 @@ bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_p
|
||||
return dynamic_cast<GLGizmoCut3D*>(m_gizmos[Cut].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == FuzzySkin)
|
||||
return dynamic_cast<GLGizmoFuzzySkin*>(m_gizmos[FuzzySkin].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == TextureDisplacement)
|
||||
return dynamic_cast<GLGizmoTextureDisplacement*>(m_gizmos[TextureDisplacement].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == MeshBoolean)
|
||||
return dynamic_cast<GLGizmoMeshBoolean*>(m_gizmos[MeshBoolean].get())->gizmo_event(action, mouse_position, shift_down, alt_down, control_down);
|
||||
else if (m_current == BrimEars)
|
||||
@@ -537,6 +546,7 @@ bool GLGizmosManager::is_paint_gizmo()
|
||||
return m_current == EType::FdmSupports ||
|
||||
m_current == EType::MmSegmentation ||
|
||||
m_current == EType::FuzzySkin ||
|
||||
m_current == EType::TextureDisplacement ||
|
||||
m_current == EType::Seam;
|
||||
}
|
||||
|
||||
@@ -1486,6 +1496,8 @@ std::string get_name_from_gizmo_etype(GLGizmosManager::EType type)
|
||||
return "Color Painting";
|
||||
case GLGizmosManager::EType::FuzzySkin:
|
||||
return "Fuzzy Skin Painting";
|
||||
case GLGizmosManager::EType::TextureDisplacement:
|
||||
return "Texture Displacement";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
Seam,
|
||||
FuzzySkin,
|
||||
MmSegmentation,
|
||||
TextureDisplacement,
|
||||
Emboss,
|
||||
Svg,
|
||||
Measure,
|
||||
|
||||
88
src/slic3r/GUI/Jobs/TextureDisplacementBakeJob.cpp
Normal file
88
src/slic3r/GUI/Jobs/TextureDisplacementBakeJob.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "TextureDisplacementBakeJob.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
TextureDisplacementBakeJob::TextureDisplacementBakeJob(TextureDisplacementBakeInput &&input, std::function<void()> on_finished)
|
||||
: m_input(std::move(input)), m_on_finished(std::move(on_finished))
|
||||
{
|
||||
}
|
||||
|
||||
void TextureDisplacementBakeJob::process(Ctl &ctl)
|
||||
{
|
||||
ctl.update_status(0, _u8L("Baking texture displacement"));
|
||||
|
||||
// Only ever touches m_input (captured by value before this job was queued) and local state --
|
||||
// never the live Model -- so this is safe to run concurrently with the UI thread.
|
||||
m_result = TriangleMesh(build_texture_displacement(m_input.base_mesh, m_input.layers, m_input.facets_data));
|
||||
}
|
||||
|
||||
void TextureDisplacementBakeJob::finalize(bool canceled, std::exception_ptr &eptr)
|
||||
{
|
||||
struct OnExit
|
||||
{
|
||||
std::function<void()> fn;
|
||||
~OnExit() { if (fn) fn(); }
|
||||
} on_exit{m_on_finished};
|
||||
|
||||
if (canceled || eptr || m_result.empty())
|
||||
return;
|
||||
|
||||
Plater *plater = wxGetApp().plater();
|
||||
|
||||
Plater::TakeSnapshot snapshot(plater, _u8L("Bake texture displacement"), UndoRedo::SnapshotType::GizmoAction);
|
||||
|
||||
ModelVolume *volume = get_model_volume(m_input.volume_id, plater->model().objects);
|
||||
if (volume == nullptr)
|
||||
return;
|
||||
|
||||
volume->set_mesh(std::move(m_result));
|
||||
volume->set_new_unique_id();
|
||||
volume->calculate_convex_hull();
|
||||
|
||||
// Clear the paint mask of every layer that was actually baked so a repeat bake (or the paint
|
||||
// overlay) doesn't act on triangles that no longer represent the same unbaked surface. The
|
||||
// texture layer definitions themselves (and paint outside the baked area, if any) are left
|
||||
// untouched so the user can keep sculpting with the same textures.
|
||||
for (const TextureDisplacementLayer &layer : m_input.layers)
|
||||
if (!layer.empty() && layer.slot >= 0 && layer.slot < int(TEXTURE_DISPLACEMENT_MAX_LAYERS))
|
||||
volume->texture_displacement_facet(layer.slot).reset();
|
||||
|
||||
ModelObject *object = volume->get_object();
|
||||
if (object == nullptr)
|
||||
return;
|
||||
|
||||
if (ObjectList *obj_list = wxGetApp().obj_list()) {
|
||||
const ModelObjectPtrs &objs = plater->model().objects;
|
||||
auto it = std::find(objs.begin(), objs.end(), object);
|
||||
if (it != objs.end())
|
||||
obj_list->update_info_items(size_t(it - objs.begin()));
|
||||
}
|
||||
|
||||
plater->changed_object(*object);
|
||||
}
|
||||
|
||||
void queue_texture_displacement_bake(const ModelVolume &volume, std::function<void()> on_finished)
|
||||
{
|
||||
TextureDisplacementBakeInput input;
|
||||
input.volume_id = volume.id();
|
||||
input.base_mesh = volume.mesh().its;
|
||||
input.layers = volume.texture_displacement_layers;
|
||||
for (int i = 0; i < int(TEXTURE_DISPLACEMENT_MAX_LAYERS); ++i)
|
||||
input.facets_data[size_t(i)] = volume.texture_displacement_facet(i).get_data();
|
||||
|
||||
auto &worker = wxGetApp().plater()->get_ui_job_worker();
|
||||
queue_job(worker, std::make_unique<TextureDisplacementBakeJob>(std::move(input), std::move(on_finished)));
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
51
src/slic3r/GUI/Jobs/TextureDisplacementBakeJob.hpp
Normal file
51
src/slic3r/GUI/Jobs/TextureDisplacementBakeJob.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef slic3r_TextureDisplacementBakeJob_hpp_
|
||||
#define slic3r_TextureDisplacementBakeJob_hpp_
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "libslic3r/ObjectID.hpp"
|
||||
#include "libslic3r/TextureDisplacement.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
|
||||
#include "Job.hpp"
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
// Everything process() needs, captured by value on the main thread when the job is queued so the
|
||||
// worker thread never touches the live Model concurrently with the UI (mirrors how EmbossJob's
|
||||
// DataBase is captured before process() runs).
|
||||
struct TextureDisplacementBakeInput
|
||||
{
|
||||
ObjectID volume_id;
|
||||
indexed_triangle_set base_mesh;
|
||||
std::vector<TextureDisplacementLayer> layers;
|
||||
TextureDisplacementFacetsData facets_data;
|
||||
};
|
||||
|
||||
// Bakes a volume's painted texture-displacement layers into real mesh geometry in the background,
|
||||
// then commits the result on the main thread -- mirrors EmbossJob's UpdateJob/update_volume()
|
||||
// bake-and-commit pattern (see EmbossJob.cpp).
|
||||
class TextureDisplacementBakeJob : public Job
|
||||
{
|
||||
public:
|
||||
TextureDisplacementBakeJob(TextureDisplacementBakeInput &&input, std::function<void()> on_finished);
|
||||
|
||||
void process(Ctl &ctl) override;
|
||||
void finalize(bool canceled, std::exception_ptr &eptr) override;
|
||||
|
||||
private:
|
||||
TextureDisplacementBakeInput m_input;
|
||||
TriangleMesh m_result;
|
||||
std::function<void()> m_on_finished;
|
||||
};
|
||||
|
||||
// Captures `volume`'s current mesh/layers/paint data and queues a TextureDisplacementBakeJob on
|
||||
// the app's UI job worker. `on_finished` is always called once the job settles (success, failure,
|
||||
// or cancellation), so the caller can clear its own "bake in progress" UI state. Must be called
|
||||
// from the main thread.
|
||||
void queue_texture_displacement_bake(const ModelVolume &volume, std::function<void()> on_finished);
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
#endif // slic3r_TextureDisplacementBakeJob_hpp_
|
||||
255
src/slic3r/GUI/generated/Invalidation_generated.cpp
Normal file
255
src/slic3r/GUI/generated/Invalidation_generated.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
// ===== AUTO-GENERATED by tools/config_codegen.py =====
|
||||
|
||||
static const std::unordered_map<std::string, std::vector<PrintStep>> s_print_steps_map = {
|
||||
{"accel_to_decel_enable", {psGCodeExport}},
|
||||
{"accel_to_decel_factor", {psGCodeExport}},
|
||||
{"activate_air_filtration", {psGCodeExport}},
|
||||
{"activate_air_filtration_during_print", {psGCodeExport}},
|
||||
{"activate_air_filtration_on_completion", {psGCodeExport}},
|
||||
{"activate_chamber_temp_control", {psGCodeExport}},
|
||||
{"additional_cooling_fan_speed", {psGCodeExport}},
|
||||
{"bed_temperature_formula", {psGCodeExport}},
|
||||
{"before_layer_change_gcode", {psGCodeExport}},
|
||||
{"bridge_acceleration", {psGCodeExport}},
|
||||
{"chamber_temperature", {psSkirtBrim, psWipeTower, psGCodeExport}},
|
||||
{"change_filament_gcode", {psGCodeExport}},
|
||||
{"close_fan_the_first_x_layers", {psGCodeExport}},
|
||||
{"complete_print_exhaust_fan_speed", {psGCodeExport}},
|
||||
{"cool_plate_temp", {psSkirtBrim, psWipeTower}},
|
||||
{"cool_plate_temp_initial_layer", {psGCodeExport}},
|
||||
{"curr_bed_type", {psGCodeExport}},
|
||||
{"default_acceleration", {psGCodeExport}},
|
||||
{"default_filament_colour", {psGCodeExport}},
|
||||
{"deretraction_speed", {psGCodeExport}},
|
||||
{"disable_m73", {psGCodeExport}},
|
||||
{"dont_slow_down_outer_wall", {psGCodeExport}},
|
||||
{"draft_shield", {psSkirtBrim}},
|
||||
{"during_print_exhaust_fan_speed", {psGCodeExport}},
|
||||
{"enable_arc_fitting", {psSkirtBrim}},
|
||||
{"enable_filament_ramming", {psSkirtBrim, psWipeTower}},
|
||||
{"enable_long_retraction_when_cut", {psGCodeExport}},
|
||||
{"enable_overhang_bridge_fan", {psGCodeExport}},
|
||||
{"enable_pressure_advance", {psGCodeExport}},
|
||||
{"enable_prime_tower", {psSkirtBrim, psWipeTower}},
|
||||
{"enable_tower_interface_features", {psSkirtBrim, psWipeTower}},
|
||||
{"enable_wrapping_detection", {psSkirtBrim, psWipeTower}},
|
||||
{"eng_plate_temp", {psSkirtBrim, psWipeTower}},
|
||||
{"eng_plate_temp_initial_layer", {psGCodeExport}},
|
||||
{"exclude_object", {psGCodeExport}},
|
||||
{"extruder_ams_count", {psSkirtBrim, psWipeTower}},
|
||||
{"extruder_clearance_height_to_lid", {psGCodeExport}},
|
||||
{"extruder_clearance_height_to_rod", {psGCodeExport}},
|
||||
{"extruder_clearance_radius", {psGCodeExport}},
|
||||
{"extruder_colour", {psGCodeExport}},
|
||||
{"extruder_offset", {psGCodeExport}},
|
||||
{"extrusion_rate_smoothing_external_perimeter_only", {psGCodeExport}},
|
||||
{"fan_cooling_layer_time", {psGCodeExport}},
|
||||
{"fan_kickstart", {psGCodeExport}},
|
||||
{"fan_max_speed", {psGCodeExport}},
|
||||
{"fan_min_speed", {psGCodeExport}},
|
||||
{"fan_speedup_overhangs", {psGCodeExport}},
|
||||
{"fan_speedup_time", {psGCodeExport}},
|
||||
{"filament_adaptive_volumetric_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_adhesiveness_category", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_change_length", {psWipeTower}},
|
||||
{"filament_colour", {psGCodeExport}},
|
||||
{"filament_cooling_final_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_cooling_initial_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_cooling_moves", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_cost", {psGCodeExport}},
|
||||
{"filament_density", {psGCodeExport}},
|
||||
{"filament_diameter", {psGCodeExport}},
|
||||
{"filament_end_gcode", {psGCodeExport}},
|
||||
{"filament_flow_ratio", {psGCodeExport}},
|
||||
{"filament_is_support", {psWipeTower}},
|
||||
{"filament_loading_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_loading_speed_start", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_map", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_map_mode", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_max_volumetric_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_minimal_purge_on_wipe_tower", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_multitool_ramming", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_multitool_ramming_flow", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_multitool_ramming_volume", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_notes", {psGCodeExport}},
|
||||
{"filament_printable", {psWipeTower}},
|
||||
{"filament_ramming_parameters", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_soluble", {psWipeTower}},
|
||||
{"filament_stamping_distance", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_stamping_loading_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_start_gcode", {psGCodeExport}},
|
||||
{"filament_toolchange_delay", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_tower_interface_pre_extrusion_dist", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_tower_interface_pre_extrusion_length", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_tower_interface_print_temp", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_tower_interface_purge_volume", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_tower_ironing_area", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_type", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_unloading_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"filament_unloading_speed_start", {psSkirtBrim, psWipeTower}},
|
||||
{"filename_format", {psGCodeExport}},
|
||||
{"first_layer_print_sequence", {psSkirtBrim, psWipeTower}},
|
||||
{"flush_into_infill", {psSkirtBrim, psWipeTower}},
|
||||
{"flush_into_support", {psSkirtBrim, psWipeTower}},
|
||||
{"flush_volumes_matrix", {psSkirtBrim, psWipeTower}},
|
||||
{"full_fan_speed_layer", {psGCodeExport}},
|
||||
{"gcode_add_line_number", {psGCodeExport}},
|
||||
{"gcode_comments", {psGCodeExport}},
|
||||
{"gcode_flavor", {psSkirtBrim, psWipeTower}},
|
||||
{"gcode_label_objects", {psGCodeExport}},
|
||||
{"grab_length", {psGCodeExport}},
|
||||
{"hot_plate_temp", {psSkirtBrim, psWipeTower}},
|
||||
{"hot_plate_temp_initial_layer", {psGCodeExport}},
|
||||
{"idle_temperature", {psSkirtBrim, psWipeTower}},
|
||||
{"independent_support_layer_height", {psWipeTower}},
|
||||
{"initial_layer_acceleration", {psGCodeExport}},
|
||||
{"initial_layer_infill_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"initial_layer_line_width", {psSkirtBrim}},
|
||||
{"initial_layer_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"initial_layer_travel_acceleration", {psSkirtBrim, psWipeTower}},
|
||||
{"initial_layer_travel_jerk", {psSkirtBrim, psWipeTower}},
|
||||
{"initial_layer_travel_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"inner_wall_acceleration", {psGCodeExport}},
|
||||
{"internal_bridge_fan_speed", {psGCodeExport}},
|
||||
{"internal_solid_infill_acceleration", {psGCodeExport}},
|
||||
{"ironing_fan_speed", {psGCodeExport}},
|
||||
{"is_infill_first", {psGCodeExport}},
|
||||
{"layer_change_gcode", {psGCodeExport}},
|
||||
{"long_retractions_when_cut", {psGCodeExport}},
|
||||
{"machine_end_gcode", {psGCodeExport}},
|
||||
{"machine_start_gcode", {psGCodeExport}},
|
||||
{"manual_filament_change", {psGCodeExport}},
|
||||
{"max_layer_height", {psSkirtBrim}},
|
||||
{"max_travel_detour_distance", {psGCodeExport}},
|
||||
{"max_volumetric_extrusion_rate_slope", {psGCodeExport}},
|
||||
{"max_volumetric_extrusion_rate_slope_segment_length", {psGCodeExport}},
|
||||
{"min_layer_height", {psSkirtBrim}},
|
||||
{"min_skirt_length", {psSkirtBrim}},
|
||||
{"nozzle_height", {psGCodeExport}},
|
||||
{"nozzle_hrc", {psGCodeExport}},
|
||||
{"nozzle_temperature", {psSkirtBrim, psWipeTower}},
|
||||
{"nozzle_temperature_initial_layer", {psSkirtBrim, psWipeTower}},
|
||||
{"nozzle_volume", {psGCodeExport}},
|
||||
{"ooze_prevention", {psSkirtBrim}},
|
||||
{"other_layers_print_sequence", {psSkirtBrim, psWipeTower}},
|
||||
{"other_layers_print_sequence_nums", {psSkirtBrim, psWipeTower}},
|
||||
{"outer_wall_acceleration", {psGCodeExport}},
|
||||
{"overhang_fan_speed", {psGCodeExport}},
|
||||
{"overhang_fan_threshold", {psGCodeExport}},
|
||||
{"part_cooling_fan_min_pwm", {psGCodeExport}},
|
||||
{"post_process", {psGCodeExport}},
|
||||
{"preheat_steps", {psGCodeExport}},
|
||||
{"preheat_time", {psGCodeExport}},
|
||||
{"pressure_advance", {psGCodeExport}},
|
||||
{"prime_tower_brim_width", {psSkirtBrim, psWipeTower}},
|
||||
{"prime_tower_enable_framework", {psSkirtBrim, psWipeTower}},
|
||||
{"prime_tower_flat_ironing", {psSkirtBrim, psWipeTower}},
|
||||
{"prime_tower_skip_points", {psSkirtBrim, psWipeTower}},
|
||||
{"prime_tower_width", {psSkirtBrim, psWipeTower}},
|
||||
{"prime_volume", {psSkirtBrim, psWipeTower}},
|
||||
{"print_order", {psSkirtBrim}},
|
||||
{"print_sequence", {psSkirtBrim, psWipeTower}},
|
||||
{"printer_notes", {psGCodeExport}},
|
||||
{"printing_by_object_gcode", {psGCodeExport}},
|
||||
{"purge_in_prime_tower", {psSkirtBrim, psWipeTower}},
|
||||
{"reduce_crossing_wall", {psGCodeExport}},
|
||||
{"reduce_fan_stop_start_freq", {psGCodeExport}},
|
||||
{"reduce_infill_retraction", {psGCodeExport}},
|
||||
{"required_nozzle_HRC", {psGCodeExport}},
|
||||
{"resolution", {psSkirtBrim}},
|
||||
{"retract_before_wipe", {psGCodeExport}},
|
||||
{"retract_length_toolchange", {psGCodeExport}},
|
||||
{"retract_lift_above", {psGCodeExport}},
|
||||
{"retract_lift_below", {psGCodeExport}},
|
||||
{"retract_lift_enforce", {psGCodeExport}},
|
||||
{"retract_restart_extra", {psGCodeExport}},
|
||||
{"retract_restart_extra_toolchange", {psGCodeExport}},
|
||||
{"retract_when_changing_layer", {psGCodeExport}},
|
||||
{"retraction_distances_when_cut", {psGCodeExport}},
|
||||
{"retraction_length", {psGCodeExport}},
|
||||
{"retraction_minimum_travel", {psGCodeExport}},
|
||||
{"retraction_speed", {psGCodeExport}},
|
||||
{"role_based_wipe_speed", {psGCodeExport}},
|
||||
{"seam_gap", {psGCodeExport}},
|
||||
{"single_extruder_multi_material", {psSkirtBrim, psWipeTower}},
|
||||
{"single_extruder_multi_material_priming", {psGCodeExport}},
|
||||
{"single_loop_draft_shield", {psSkirtBrim}},
|
||||
{"skirt_distance", {psSkirtBrim}},
|
||||
{"skirt_height", {psSkirtBrim}},
|
||||
{"skirt_loops", {psSkirtBrim}},
|
||||
{"skirt_speed", {psSkirtBrim}},
|
||||
{"skirt_start_angle", {psSkirtBrim}},
|
||||
{"skirt_type", {psSkirtBrim}},
|
||||
{"slow_down_for_layer_cooling", {psGCodeExport}},
|
||||
{"slow_down_layer_time", {psGCodeExport}},
|
||||
{"slow_down_layers", {psSkirtBrim, psWipeTower}},
|
||||
{"slow_down_min_speed", {psGCodeExport}},
|
||||
{"sparse_infill_acceleration", {psGCodeExport}},
|
||||
{"standby_temperature_delta", {psGCodeExport}},
|
||||
{"supertack_plate_temp", {psSkirtBrim, psWipeTower}},
|
||||
{"supertack_plate_temp_initial_layer", {psGCodeExport}},
|
||||
{"support_material_interface_fan_speed", {psGCodeExport}},
|
||||
{"support_multi_bed_types", {psSkirtBrim, psWipeTower}},
|
||||
{"textured_cool_plate_temp", {psSkirtBrim, psWipeTower}},
|
||||
{"textured_cool_plate_temp_initial_layer", {psGCodeExport}},
|
||||
{"textured_plate_temp", {psSkirtBrim, psWipeTower}},
|
||||
{"textured_plate_temp_initial_layer", {psGCodeExport}},
|
||||
{"thumbnails", {psGCodeExport}},
|
||||
{"thumbnails_format", {psGCodeExport}},
|
||||
{"time_lapse_gcode", {psGCodeExport}},
|
||||
{"tool_change_on_wipe_tower", {psSkirtBrim, psWipeTower}},
|
||||
{"top_surface_acceleration", {psGCodeExport}},
|
||||
{"travel_acceleration", {psGCodeExport}},
|
||||
{"travel_slope", {psGCodeExport}},
|
||||
{"travel_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"travel_speed_z", {psSkirtBrim, psWipeTower}},
|
||||
{"upward_compatible_machine", {psGCodeExport}},
|
||||
{"use_firmware_retraction", {psGCodeExport}},
|
||||
{"use_relative_e_distances", {psGCodeExport}},
|
||||
{"volumetric_speed_coefficients", {psGCodeExport}},
|
||||
{"wall_sequence", {psSkirtBrim}},
|
||||
{"wipe", {psGCodeExport}},
|
||||
{"wipe_distance", {psGCodeExport}},
|
||||
{"wipe_on_loops", {psGCodeExport}},
|
||||
{"wipe_speed", {psGCodeExport}},
|
||||
{"wipe_tower_bridging", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_cone_angle", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_extra_flow", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_extra_rib_length", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_extra_spacing", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_filament", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_fillet_wall", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_max_purge_speed", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_no_sparse_layers", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_rib_width", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_rotation_angle", {psSkirtBrim}},
|
||||
{"wipe_tower_type", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_wall_type", {psSkirtBrim, psWipeTower}},
|
||||
{"wipe_tower_x", {psSkirtBrim}},
|
||||
{"wipe_tower_y", {psSkirtBrim}},
|
||||
{"wiping_volumes_extruders", {psSkirtBrim, psWipeTower}},
|
||||
{"wrapping_detection_gcode", {psGCodeExport}},
|
||||
{"z_hop", {psGCodeExport}},
|
||||
{"z_offset", {psSkirtBrim, psWipeTower}},
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, std::vector<PrintObjectStep>> s_object_steps_map = {
|
||||
{"enable_arc_fitting", {posSupportMaterial, posInfill, posPerimeters}},
|
||||
{"filament_change_length", {posSupportMaterial}},
|
||||
{"filament_is_support", {posSupportMaterial}},
|
||||
{"filament_printable", {posSupportMaterial}},
|
||||
{"filament_shrink", {posSlice}},
|
||||
{"filament_shrinkage_compensation_z", {posSlice}},
|
||||
{"filament_soluble", {posSupportMaterial}},
|
||||
{"independent_support_layer_height", {posSupportMaterial}},
|
||||
{"initial_layer_line_width", {posSupportMaterial, posInfill, posPerimeters}},
|
||||
{"initial_layer_print_height", {posSlice}},
|
||||
{"max_layer_height", {posSupportMaterial, posInfill, posPerimeters}},
|
||||
{"min_layer_height", {posSupportMaterial, posInfill, posPerimeters}},
|
||||
{"nozzle_diameter", {posSlice}},
|
||||
{"precise_z_height", {posSlice}},
|
||||
{"print_order", {posSupportMaterial, posInfill, posPerimeters}},
|
||||
{"resolution", {posSupportMaterial, posInfill, posPerimeters, posSlice}},
|
||||
{"spiral_mode", {posSlice}},
|
||||
{"wall_sequence", {posSupportMaterial, posInfill, posPerimeters}},
|
||||
};
|
||||
61
src/slic3r/GUI/generated/OptionKeys_generated.cpp
Normal file
61
src/slic3r/GUI/generated/OptionKeys_generated.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// ===== AUTO-GENERATED by tools/config_codegen.py =====
|
||||
|
||||
static const std::vector<std::string> s_extruder_option_keys = {
|
||||
"default_filament_profile",
|
||||
"default_nozzle_volume_type",
|
||||
"deretraction_speed",
|
||||
"extruder_colour",
|
||||
"extruder_offset",
|
||||
"extruder_type",
|
||||
"long_retractions_when_cut",
|
||||
"max_layer_height",
|
||||
"min_layer_height",
|
||||
"nozzle_diameter",
|
||||
"nozzle_flush_dataset",
|
||||
"nozzle_type",
|
||||
"nozzle_volume",
|
||||
"retract_before_wipe",
|
||||
"retract_length_toolchange",
|
||||
"retract_lift_above",
|
||||
"retract_lift_below",
|
||||
"retract_lift_enforce",
|
||||
"retract_restart_extra",
|
||||
"retract_restart_extra_toolchange",
|
||||
"retract_when_changing_layer",
|
||||
"retraction_distances_when_cut",
|
||||
"retraction_length",
|
||||
"retraction_minimum_travel",
|
||||
"retraction_speed",
|
||||
"travel_slope",
|
||||
"wipe",
|
||||
"wipe_distance",
|
||||
"z_hop",
|
||||
"z_hop_types",
|
||||
};
|
||||
|
||||
static const std::vector<std::string> s_filament_option_keys = {
|
||||
"default_filament_profile",
|
||||
"deretraction_speed",
|
||||
"filament_colour",
|
||||
"filament_diameter",
|
||||
"long_retractions_when_cut",
|
||||
"max_layer_height",
|
||||
"min_layer_height",
|
||||
"retract_before_wipe",
|
||||
"retract_length_toolchange",
|
||||
"retract_lift_above",
|
||||
"retract_lift_below",
|
||||
"retract_lift_enforce",
|
||||
"retract_restart_extra",
|
||||
"retract_restart_extra_toolchange",
|
||||
"retract_when_changing_layer",
|
||||
"retraction_distances_when_cut",
|
||||
"retraction_length",
|
||||
"retraction_minimum_travel",
|
||||
"retraction_speed",
|
||||
"volumetric_speed_coefficients",
|
||||
"wipe",
|
||||
"wipe_distance",
|
||||
"z_hop",
|
||||
"z_hop_types",
|
||||
};
|
||||
726
src/slic3r/GUI/generated/Preset_options_generated.cpp
Normal file
726
src/slic3r/GUI/generated/Preset_options_generated.cpp
Normal file
@@ -0,0 +1,726 @@
|
||||
// ===== AUTO-GENERATED by tools/config_codegen.py =====
|
||||
|
||||
static const std::vector<std::string> s_Preset_print_options = {
|
||||
"accel_to_decel_enable",
|
||||
"accel_to_decel_factor",
|
||||
"adaptive_layer_height",
|
||||
"align_infill_direction_to_model",
|
||||
"alternate_extra_wall",
|
||||
"bbl_calib_mark_logo",
|
||||
"bed_temperature_formula",
|
||||
"bottom_shell_layers",
|
||||
"bottom_shell_thickness",
|
||||
"bottom_solid_infill_flow_ratio",
|
||||
"bottom_surface_density",
|
||||
"bottom_surface_pattern",
|
||||
"bridge_acceleration",
|
||||
"bridge_angle",
|
||||
"bridge_density",
|
||||
"bridge_flow",
|
||||
"bridge_no_support",
|
||||
"bridge_speed",
|
||||
"brim_ears",
|
||||
"brim_ears_detection_length",
|
||||
"brim_ears_max_angle",
|
||||
"brim_flow_ratio",
|
||||
"brim_object_gap",
|
||||
"brim_type",
|
||||
"brim_use_efc_outline",
|
||||
"brim_width",
|
||||
"calib_flowrate_topinfill_special_order",
|
||||
"combine_brims",
|
||||
"compatible_machine_expression_group",
|
||||
"compatible_printers",
|
||||
"compatible_printers_condition",
|
||||
"compatible_prints",
|
||||
"compatible_process_expression_group",
|
||||
"cooling_tube_length",
|
||||
"cooling_tube_retraction",
|
||||
"counterbore_hole_bridging",
|
||||
"curr_bed_type",
|
||||
"default_acceleration",
|
||||
"default_bed_type",
|
||||
"default_filament_profile",
|
||||
"default_jerk",
|
||||
"default_junction_deviation",
|
||||
"default_nozzle_volume_type",
|
||||
"default_print_profile",
|
||||
"deretraction_speed",
|
||||
"detect_narrow_internal_solid_infill",
|
||||
"detect_overhang_wall",
|
||||
"detect_thin_wall",
|
||||
"different_settings_to_system",
|
||||
"dont_filter_internal_bridges",
|
||||
"draft_shield",
|
||||
"elefant_foot_compensation",
|
||||
"elefant_foot_compensation_layers",
|
||||
"elefant_foot_layers_density",
|
||||
"emit_machine_limits_to_gcode",
|
||||
"enable_arc_fitting",
|
||||
"enable_extra_bridge_layer",
|
||||
"enable_filament_dynamic_map",
|
||||
"enable_filament_ramming",
|
||||
"enable_long_retraction_when_cut",
|
||||
"enable_overhang_speed",
|
||||
"enable_prime_tower",
|
||||
"enable_support",
|
||||
"enable_tower_interface_cooldown_during_tower",
|
||||
"enable_tower_interface_features",
|
||||
"enable_wrapping_detection",
|
||||
"enforce_support_layers",
|
||||
"ensure_vertical_shell_thickness",
|
||||
"exclude_object",
|
||||
"extra_loading_move",
|
||||
"extra_perimeters_on_overhangs",
|
||||
"extra_solid_infills",
|
||||
"extruder",
|
||||
"extruder_ams_count",
|
||||
"extruder_colour",
|
||||
"extruder_offset",
|
||||
"extruder_type",
|
||||
"extruder_variant_list",
|
||||
"extrusion_rate_smoothing_external_perimeter_only",
|
||||
"filament_colour",
|
||||
"filament_colour_type",
|
||||
"filament_extruder_id",
|
||||
"filament_flush_temp",
|
||||
"filament_ids",
|
||||
"filament_map",
|
||||
"filament_map_mode",
|
||||
"filament_multi_colour",
|
||||
"filament_ramming_parameters",
|
||||
"filament_self_index",
|
||||
"filament_settings_id",
|
||||
"filename_format",
|
||||
"fill_multiline",
|
||||
"filter_out_gap_fill",
|
||||
"first_layer_flow_ratio",
|
||||
"first_layer_print_sequence",
|
||||
"first_layer_sequence_choice",
|
||||
"flush_into_infill",
|
||||
"flush_into_objects",
|
||||
"flush_into_support",
|
||||
"flush_multiplier",
|
||||
"flush_volumes_matrix",
|
||||
"flush_volumes_vector",
|
||||
"fuzzy_skin",
|
||||
"fuzzy_skin_first_layer",
|
||||
"fuzzy_skin_layers_between_ripple_offset",
|
||||
"fuzzy_skin_mode",
|
||||
"fuzzy_skin_noise_type",
|
||||
"fuzzy_skin_octaves",
|
||||
"fuzzy_skin_persistence",
|
||||
"fuzzy_skin_point_distance",
|
||||
"fuzzy_skin_ripple_offset",
|
||||
"fuzzy_skin_ripples_per_layer",
|
||||
"fuzzy_skin_scale",
|
||||
"fuzzy_skin_thickness",
|
||||
"gap_fill_flow_ratio",
|
||||
"gap_fill_target",
|
||||
"gap_infill_speed",
|
||||
"gcode_add_line_number",
|
||||
"gcode_comments",
|
||||
"gcode_label_objects",
|
||||
"grab_length",
|
||||
"gyroid_optimized",
|
||||
"has_filament_switcher",
|
||||
"has_scarf_joint_seam",
|
||||
"head_wrap_detect_zone",
|
||||
"high_current_on_filament_swap",
|
||||
"hole_to_polyhole",
|
||||
"hole_to_polyhole_threshold",
|
||||
"hole_to_polyhole_twisted",
|
||||
"host_type",
|
||||
"independent_support_layer_height",
|
||||
"infill_anchor",
|
||||
"infill_anchor_max",
|
||||
"infill_combination",
|
||||
"infill_combination_max_layer_height",
|
||||
"infill_direction",
|
||||
"infill_jerk",
|
||||
"infill_lock_depth",
|
||||
"infill_overhang_angle",
|
||||
"infill_shift_step",
|
||||
"infill_wall_overlap",
|
||||
"inherits",
|
||||
"inherits_group",
|
||||
"initial_layer_acceleration",
|
||||
"initial_layer_infill_speed",
|
||||
"initial_layer_jerk",
|
||||
"initial_layer_line_width",
|
||||
"initial_layer_min_bead_width",
|
||||
"initial_layer_print_height",
|
||||
"initial_layer_speed",
|
||||
"initial_layer_travel_acceleration",
|
||||
"initial_layer_travel_jerk",
|
||||
"initial_layer_travel_speed",
|
||||
"inner_wall_acceleration",
|
||||
"inner_wall_flow_ratio",
|
||||
"inner_wall_jerk",
|
||||
"inner_wall_line_width",
|
||||
"inner_wall_speed",
|
||||
"input_shaping_damp_x",
|
||||
"input_shaping_damp_y",
|
||||
"input_shaping_emit",
|
||||
"input_shaping_freq_x",
|
||||
"input_shaping_freq_y",
|
||||
"input_shaping_type",
|
||||
"interface_shells",
|
||||
"interlocking_beam",
|
||||
"interlocking_beam_layer_count",
|
||||
"interlocking_beam_width",
|
||||
"interlocking_boundary_avoidance",
|
||||
"interlocking_depth",
|
||||
"interlocking_orientation",
|
||||
"internal_bridge_angle",
|
||||
"internal_bridge_density",
|
||||
"internal_bridge_flow",
|
||||
"internal_bridge_speed",
|
||||
"internal_solid_infill_acceleration",
|
||||
"internal_solid_infill_flow_ratio",
|
||||
"internal_solid_infill_line_width",
|
||||
"internal_solid_infill_pattern",
|
||||
"internal_solid_infill_speed",
|
||||
"ironing_angle",
|
||||
"ironing_angle_fixed",
|
||||
"ironing_expansion",
|
||||
"ironing_flow",
|
||||
"ironing_inset",
|
||||
"ironing_pattern",
|
||||
"ironing_spacing",
|
||||
"ironing_speed",
|
||||
"ironing_type",
|
||||
"is_infill_first",
|
||||
"lateral_lattice_angle_1",
|
||||
"lateral_lattice_angle_2",
|
||||
"layer_height",
|
||||
"line_width",
|
||||
"long_retractions_when_cut",
|
||||
"machine_load_filament_time",
|
||||
"machine_max_acceleration_e",
|
||||
"machine_max_acceleration_extruding",
|
||||
"machine_max_acceleration_retracting",
|
||||
"machine_max_acceleration_travel",
|
||||
"machine_max_acceleration_x",
|
||||
"machine_max_acceleration_y",
|
||||
"machine_max_acceleration_z",
|
||||
"machine_max_jerk_e",
|
||||
"machine_max_jerk_x",
|
||||
"machine_max_jerk_y",
|
||||
"machine_max_jerk_z",
|
||||
"machine_max_junction_deviation",
|
||||
"machine_max_speed_e",
|
||||
"machine_max_speed_x",
|
||||
"machine_max_speed_y",
|
||||
"machine_max_speed_z",
|
||||
"machine_min_extruding_rate",
|
||||
"machine_min_travel_rate",
|
||||
"machine_tool_change_time",
|
||||
"machine_unload_filament_time",
|
||||
"make_overhang_printable",
|
||||
"make_overhang_printable_angle",
|
||||
"make_overhang_printable_hole_size",
|
||||
"manual_filament_change",
|
||||
"master_extruder_id",
|
||||
"max_bridge_length",
|
||||
"max_layer_height",
|
||||
"max_resonance_avoidance_speed",
|
||||
"max_travel_detour_distance",
|
||||
"max_volumetric_extrusion_rate_slope",
|
||||
"max_volumetric_extrusion_rate_slope_segment_length",
|
||||
"min_bead_width",
|
||||
"min_feature_size",
|
||||
"min_layer_height",
|
||||
"min_length_factor",
|
||||
"min_resonance_avoidance_speed",
|
||||
"min_skirt_length",
|
||||
"min_width_top_surface",
|
||||
"minimum_sparse_infill_area",
|
||||
"mmu_segmented_region_interlocking_depth",
|
||||
"mmu_segmented_region_max_width",
|
||||
"notes",
|
||||
"nozzle_diameter",
|
||||
"nozzle_flush_dataset",
|
||||
"nozzle_height",
|
||||
"nozzle_volume",
|
||||
"nozzle_volume_type",
|
||||
"only_one_wall_first_layer",
|
||||
"only_one_wall_top",
|
||||
"ooze_prevention",
|
||||
"other_layers_print_sequence",
|
||||
"other_layers_print_sequence_nums",
|
||||
"other_layers_sequence_choice",
|
||||
"outer_wall_acceleration",
|
||||
"outer_wall_flow_ratio",
|
||||
"outer_wall_jerk",
|
||||
"outer_wall_line_width",
|
||||
"outer_wall_speed",
|
||||
"overhang_1_4_speed",
|
||||
"overhang_2_4_speed",
|
||||
"overhang_3_4_speed",
|
||||
"overhang_4_4_speed",
|
||||
"overhang_flow_ratio",
|
||||
"overhang_reverse",
|
||||
"overhang_reverse_internal_only",
|
||||
"overhang_reverse_threshold",
|
||||
"parking_pos_retraction",
|
||||
"physical_extruder_map",
|
||||
"post_process",
|
||||
"precise_outer_wall",
|
||||
"precise_z_height",
|
||||
"preheat_steps",
|
||||
"preheat_time",
|
||||
"prime_tower_brim_width",
|
||||
"prime_tower_enable_framework",
|
||||
"prime_tower_flat_ironing",
|
||||
"prime_tower_infill_gap",
|
||||
"prime_tower_skip_points",
|
||||
"prime_tower_width",
|
||||
"prime_volume",
|
||||
"print_compatible_printers",
|
||||
"print_extruder_id",
|
||||
"print_extruder_variant",
|
||||
"print_flow_ratio",
|
||||
"print_order",
|
||||
"print_sequence",
|
||||
"print_settings_id",
|
||||
"printer_extruder_id",
|
||||
"printer_extruder_variant",
|
||||
"printer_model",
|
||||
"printer_settings_id",
|
||||
"printer_variant",
|
||||
"process_change_extrusion_role_gcode",
|
||||
"purge_in_prime_tower",
|
||||
"raft_contact_distance",
|
||||
"raft_expansion",
|
||||
"raft_first_layer_density",
|
||||
"raft_first_layer_expansion",
|
||||
"raft_layers",
|
||||
"reduce_crossing_wall",
|
||||
"reduce_infill_retraction",
|
||||
"resolution",
|
||||
"resonance_avoidance",
|
||||
"retract_before_wipe",
|
||||
"retract_length_toolchange",
|
||||
"retract_lift_above",
|
||||
"retract_lift_below",
|
||||
"retract_lift_enforce",
|
||||
"retract_restart_extra",
|
||||
"retract_restart_extra_toolchange",
|
||||
"retract_when_changing_layer",
|
||||
"retraction_distances_when_cut",
|
||||
"retraction_length",
|
||||
"retraction_minimum_travel",
|
||||
"retraction_speed",
|
||||
"role_based_wipe_speed",
|
||||
"scarf_angle_threshold",
|
||||
"scarf_joint_flow_ratio",
|
||||
"scarf_joint_speed",
|
||||
"scarf_overhang_threshold",
|
||||
"seam_gap",
|
||||
"seam_position",
|
||||
"seam_slope_conditional",
|
||||
"seam_slope_entire_loop",
|
||||
"seam_slope_inner_walls",
|
||||
"seam_slope_min_length",
|
||||
"seam_slope_start_height",
|
||||
"seam_slope_steps",
|
||||
"seam_slope_type",
|
||||
"set_other_flow_ratios",
|
||||
"silent_mode",
|
||||
"single_extruder_multi_material",
|
||||
"single_extruder_multi_material_priming",
|
||||
"single_loop_draft_shield",
|
||||
"skeleton_infill_density",
|
||||
"skeleton_infill_line_width",
|
||||
"skin_infill_density",
|
||||
"skin_infill_depth",
|
||||
"skin_infill_line_width",
|
||||
"skirt_distance",
|
||||
"skirt_height",
|
||||
"skirt_loops",
|
||||
"skirt_speed",
|
||||
"skirt_start_angle",
|
||||
"skirt_type",
|
||||
"slice_closing_radius",
|
||||
"slicing_mode",
|
||||
"slow_down_layers",
|
||||
"slowdown_for_curled_perimeters",
|
||||
"small_area_infill_flow_compensation",
|
||||
"small_area_infill_flow_compensation_model",
|
||||
"small_perimeter_speed",
|
||||
"small_perimeter_threshold",
|
||||
"solid_infill_direction",
|
||||
"solid_infill_filament",
|
||||
"solid_infill_rotate_template",
|
||||
"spaghetti_detector",
|
||||
"sparse_infill_acceleration",
|
||||
"sparse_infill_density",
|
||||
"sparse_infill_filament",
|
||||
"sparse_infill_flow_ratio",
|
||||
"sparse_infill_line_width",
|
||||
"sparse_infill_pattern",
|
||||
"sparse_infill_rotate_template",
|
||||
"sparse_infill_speed",
|
||||
"spiral_finishing_flow_ratio",
|
||||
"spiral_mode",
|
||||
"spiral_mode_max_xy_smoothing",
|
||||
"spiral_mode_smooth",
|
||||
"spiral_starting_flow_ratio",
|
||||
"staggered_inner_seams",
|
||||
"standby_temperature_delta",
|
||||
"start_end_points",
|
||||
"support_angle",
|
||||
"support_base_pattern",
|
||||
"support_base_pattern_spacing",
|
||||
"support_bottom_interface_spacing",
|
||||
"support_bottom_z_distance",
|
||||
"support_critical_regions_only",
|
||||
"support_expansion",
|
||||
"support_filament",
|
||||
"support_flow_ratio",
|
||||
"support_interface_bottom_layers",
|
||||
"support_interface_filament",
|
||||
"support_interface_flow_ratio",
|
||||
"support_interface_loop_pattern",
|
||||
"support_interface_not_for_body",
|
||||
"support_interface_pattern",
|
||||
"support_interface_spacing",
|
||||
"support_interface_speed",
|
||||
"support_interface_top_layers",
|
||||
"support_ironing",
|
||||
"support_ironing_flow",
|
||||
"support_ironing_pattern",
|
||||
"support_ironing_spacing",
|
||||
"support_line_width",
|
||||
"support_object_first_layer_gap",
|
||||
"support_object_skip_flush",
|
||||
"support_object_xy_distance",
|
||||
"support_on_build_plate_only",
|
||||
"support_remove_small_overhang",
|
||||
"support_speed",
|
||||
"support_style",
|
||||
"support_threshold_angle",
|
||||
"support_threshold_overlap",
|
||||
"support_top_z_distance",
|
||||
"support_type",
|
||||
"symmetric_infill_y_axis",
|
||||
"thick_bridges",
|
||||
"thick_internal_bridges",
|
||||
"thumbnails_format",
|
||||
"timelapse_type",
|
||||
"tool_change_on_wipe_tower",
|
||||
"top_bottom_infill_wall_overlap",
|
||||
"top_shell_layers",
|
||||
"top_shell_thickness",
|
||||
"top_solid_infill_flow_ratio",
|
||||
"top_surface_acceleration",
|
||||
"top_surface_density",
|
||||
"top_surface_jerk",
|
||||
"top_surface_line_width",
|
||||
"top_surface_pattern",
|
||||
"top_surface_speed",
|
||||
"travel_acceleration",
|
||||
"travel_jerk",
|
||||
"travel_slope",
|
||||
"travel_speed",
|
||||
"travel_speed_z",
|
||||
"tree_support_angle_slow",
|
||||
"tree_support_auto_brim",
|
||||
"tree_support_branch_angle",
|
||||
"tree_support_branch_angle_organic",
|
||||
"tree_support_branch_diameter",
|
||||
"tree_support_branch_diameter_angle",
|
||||
"tree_support_branch_diameter_organic",
|
||||
"tree_support_branch_distance",
|
||||
"tree_support_branch_distance_organic",
|
||||
"tree_support_brim_width",
|
||||
"tree_support_tip_diameter",
|
||||
"tree_support_top_rate",
|
||||
"tree_support_wall_count",
|
||||
"tree_support_with_infill",
|
||||
"upward_compatible_machine",
|
||||
"volumetric_speed_coefficients",
|
||||
"wall_direction",
|
||||
"wall_distribution_count",
|
||||
"wall_filament",
|
||||
"wall_generator",
|
||||
"wall_loops",
|
||||
"wall_maximum_deviation",
|
||||
"wall_maximum_resolution",
|
||||
"wall_sequence",
|
||||
"wall_transition_angle",
|
||||
"wall_transition_filter_deviation",
|
||||
"wall_transition_length",
|
||||
"wipe",
|
||||
"wipe_before_external_loop",
|
||||
"wipe_distance",
|
||||
"wipe_on_loops",
|
||||
"wipe_speed",
|
||||
"wipe_tower_bridging",
|
||||
"wipe_tower_cone_angle",
|
||||
"wipe_tower_extra_flow",
|
||||
"wipe_tower_extra_rib_length",
|
||||
"wipe_tower_extra_spacing",
|
||||
"wipe_tower_filament",
|
||||
"wipe_tower_fillet_wall",
|
||||
"wipe_tower_max_purge_speed",
|
||||
"wipe_tower_no_sparse_layers",
|
||||
"wipe_tower_rib_width",
|
||||
"wipe_tower_rotation_angle",
|
||||
"wipe_tower_type",
|
||||
"wipe_tower_wall_type",
|
||||
"wipe_tower_x",
|
||||
"wipe_tower_y",
|
||||
"wiping_volumes_extruders",
|
||||
"wrapping_detection_layers",
|
||||
"wrapping_exclude_area",
|
||||
"xy_contour_compensation",
|
||||
"xy_hole_compensation",
|
||||
"z_hop",
|
||||
"z_hop_types",
|
||||
"zaa_dont_alternate_fill_direction",
|
||||
"zaa_enabled",
|
||||
"zaa_min_z",
|
||||
"zaa_minimize_perimeter_height",
|
||||
};
|
||||
|
||||
static const std::vector<std::string> s_Preset_filament_options = {
|
||||
"activate_air_filtration",
|
||||
"activate_air_filtration_during_print",
|
||||
"activate_air_filtration_on_completion",
|
||||
"activate_chamber_temp_control",
|
||||
"adaptive_pressure_advance",
|
||||
"adaptive_pressure_advance_bridges",
|
||||
"adaptive_pressure_advance_model",
|
||||
"adaptive_pressure_advance_overhangs",
|
||||
"additional_cooling_fan_speed",
|
||||
"additional_fan_full_speed_layer",
|
||||
"chamber_temperature",
|
||||
"close_additional_fan_first_x_layers",
|
||||
"close_fan_the_first_x_layers",
|
||||
"compatible_printers",
|
||||
"compatible_printers_condition",
|
||||
"compatible_prints",
|
||||
"compatible_prints_condition",
|
||||
"complete_print_exhaust_fan_speed",
|
||||
"cool_plate_temp",
|
||||
"cool_plate_temp_initial_layer",
|
||||
"default_filament_colour",
|
||||
"dont_slow_down_outer_wall",
|
||||
"during_print_exhaust_fan_speed",
|
||||
"enable_overhang_bridge_fan",
|
||||
"enable_pressure_advance",
|
||||
"eng_plate_temp",
|
||||
"eng_plate_temp_initial_layer",
|
||||
"fan_cooling_layer_time",
|
||||
"fan_max_speed",
|
||||
"fan_min_speed",
|
||||
"filament_adaptive_volumetric_speed",
|
||||
"filament_adhesiveness_category",
|
||||
"filament_change_extrusion_role_gcode",
|
||||
"filament_change_length",
|
||||
"filament_colour",
|
||||
"filament_cooling_before_tower",
|
||||
"filament_cooling_final_speed",
|
||||
"filament_cooling_initial_speed",
|
||||
"filament_cooling_moves",
|
||||
"filament_cost",
|
||||
"filament_density",
|
||||
"filament_deretraction_speed",
|
||||
"filament_diameter",
|
||||
"filament_end_gcode",
|
||||
"filament_extruder_variant",
|
||||
"filament_flow_ratio",
|
||||
"filament_flush_temp",
|
||||
"filament_flush_volumetric_speed",
|
||||
"filament_ironing_flow",
|
||||
"filament_ironing_inset",
|
||||
"filament_ironing_spacing",
|
||||
"filament_ironing_speed",
|
||||
"filament_is_support",
|
||||
"filament_loading_speed",
|
||||
"filament_loading_speed_start",
|
||||
"filament_long_retractions_when_cut",
|
||||
"filament_max_volumetric_speed",
|
||||
"filament_minimal_purge_on_wipe_tower",
|
||||
"filament_multitool_ramming",
|
||||
"filament_multitool_ramming_flow",
|
||||
"filament_multitool_ramming_volume",
|
||||
"filament_notes",
|
||||
"filament_printable",
|
||||
"filament_ramming_parameters",
|
||||
"filament_retract_before_wipe",
|
||||
"filament_retract_lift_above",
|
||||
"filament_retract_lift_below",
|
||||
"filament_retract_lift_enforce",
|
||||
"filament_retract_restart_extra",
|
||||
"filament_retract_when_changing_layer",
|
||||
"filament_retraction_distances_when_cut",
|
||||
"filament_retraction_length",
|
||||
"filament_retraction_minimum_travel",
|
||||
"filament_retraction_speed",
|
||||
"filament_shrink",
|
||||
"filament_shrinkage_compensation_z",
|
||||
"filament_soluble",
|
||||
"filament_stamping_distance",
|
||||
"filament_stamping_loading_speed",
|
||||
"filament_start_gcode",
|
||||
"filament_toolchange_delay",
|
||||
"filament_tower_interface_pre_extrusion_dist",
|
||||
"filament_tower_interface_pre_extrusion_length",
|
||||
"filament_tower_interface_print_temp",
|
||||
"filament_tower_interface_purge_volume",
|
||||
"filament_tower_ironing_area",
|
||||
"filament_type",
|
||||
"filament_unloading_speed",
|
||||
"filament_unloading_speed_start",
|
||||
"filament_vendor",
|
||||
"filament_wipe",
|
||||
"filament_wipe_distance",
|
||||
"filament_z_hop",
|
||||
"filament_z_hop_types",
|
||||
"first_x_layer_fan_speed",
|
||||
"full_fan_speed_layer",
|
||||
"hot_plate_temp",
|
||||
"hot_plate_temp_initial_layer",
|
||||
"idle_temperature",
|
||||
"inherits",
|
||||
"internal_bridge_fan_speed",
|
||||
"ironing_fan_speed",
|
||||
"long_retractions_when_ec",
|
||||
"nozzle_temperature",
|
||||
"nozzle_temperature_initial_layer",
|
||||
"nozzle_temperature_range_high",
|
||||
"nozzle_temperature_range_low",
|
||||
"overhang_fan_speed",
|
||||
"overhang_fan_threshold",
|
||||
"pellet_flow_coefficient",
|
||||
"pressure_advance",
|
||||
"reduce_fan_stop_start_freq",
|
||||
"required_nozzle_HRC",
|
||||
"retraction_distances_when_ec",
|
||||
"slow_down_for_layer_cooling",
|
||||
"slow_down_layer_time",
|
||||
"slow_down_min_speed",
|
||||
"supertack_plate_temp",
|
||||
"supertack_plate_temp_initial_layer",
|
||||
"support_material_interface_fan_speed",
|
||||
"temperature_vitrification",
|
||||
"textured_cool_plate_temp",
|
||||
"textured_cool_plate_temp_initial_layer",
|
||||
"textured_plate_temp",
|
||||
"textured_plate_temp_initial_layer",
|
||||
"volumetric_speed_coefficients",
|
||||
};
|
||||
|
||||
static const std::vector<std::string> s_Preset_printer_options = {
|
||||
"adaptive_bed_mesh_margin",
|
||||
"auxiliary_fan",
|
||||
"bbl_use_printhost",
|
||||
"bed_custom_model",
|
||||
"bed_custom_texture",
|
||||
"bed_exclude_area",
|
||||
"bed_mesh_max",
|
||||
"bed_mesh_min",
|
||||
"bed_mesh_probe_distance",
|
||||
"bed_temperature_formula",
|
||||
"before_layer_change_gcode",
|
||||
"best_object_pos",
|
||||
"change_extrusion_role_gcode",
|
||||
"change_filament_gcode",
|
||||
"cooling_tube_length",
|
||||
"cooling_tube_retraction",
|
||||
"default_bed_type",
|
||||
"default_nozzle_volume_type",
|
||||
"default_print_profile",
|
||||
"disable_m73",
|
||||
"emit_machine_limits_to_gcode",
|
||||
"enable_filament_ramming",
|
||||
"enable_long_retraction_when_cut",
|
||||
"enable_power_loss_recovery",
|
||||
"extra_loading_move",
|
||||
"extruder_clearance_height_to_lid",
|
||||
"extruder_clearance_height_to_rod",
|
||||
"extruder_clearance_radius",
|
||||
"extruder_printable_area",
|
||||
"extruder_printable_height",
|
||||
"extruder_type",
|
||||
"extruder_variant_list",
|
||||
"fan_kickstart",
|
||||
"fan_speedup_overhangs",
|
||||
"fan_speedup_time",
|
||||
"file_start_gcode",
|
||||
"gcode_flavor",
|
||||
"grab_length",
|
||||
"head_wrap_detect_zone",
|
||||
"high_current_on_filament_swap",
|
||||
"host_type",
|
||||
"inherits",
|
||||
"layer_change_gcode",
|
||||
"long_retractions_when_cut",
|
||||
"machine_end_gcode",
|
||||
"machine_load_filament_time",
|
||||
"machine_pause_gcode",
|
||||
"machine_start_gcode",
|
||||
"machine_tool_change_time",
|
||||
"machine_unload_filament_time",
|
||||
"manual_filament_change",
|
||||
"master_extruder_id",
|
||||
"nozzle_flush_dataset",
|
||||
"nozzle_height",
|
||||
"nozzle_hrc",
|
||||
"nozzle_type",
|
||||
"nozzle_volume",
|
||||
"parking_pos_retraction",
|
||||
"part_cooling_fan_min_pwm",
|
||||
"pellet_modded_printer",
|
||||
"physical_extruder_map",
|
||||
"preferred_orientation",
|
||||
"print_host",
|
||||
"print_host_webui",
|
||||
"printable_area",
|
||||
"printable_height",
|
||||
"printer_agent",
|
||||
"printer_extruder_id",
|
||||
"printer_extruder_variant",
|
||||
"printer_model",
|
||||
"printer_notes",
|
||||
"printer_structure",
|
||||
"printer_technology",
|
||||
"printer_variant",
|
||||
"printhost_apikey",
|
||||
"printhost_authorization_type",
|
||||
"printhost_cafile",
|
||||
"printhost_password",
|
||||
"printhost_port",
|
||||
"printhost_ssl_ignore_revoke",
|
||||
"printhost_user",
|
||||
"printing_by_object_gcode",
|
||||
"purge_in_prime_tower",
|
||||
"retract_lift_enforce",
|
||||
"retraction_distances_when_cut",
|
||||
"scan_first_layer",
|
||||
"silent_mode",
|
||||
"single_extruder_multi_material",
|
||||
"support_air_filtration",
|
||||
"support_chamber_temp_control",
|
||||
"support_multi_bed_types",
|
||||
"support_object_skip_flush",
|
||||
"template_custom_gcode",
|
||||
"thumbnails",
|
||||
"thumbnails_format",
|
||||
"time_cost",
|
||||
"time_lapse_gcode",
|
||||
"tool_change_on_wipe_tower",
|
||||
"travel_slope",
|
||||
"upward_compatible_machine",
|
||||
"use_firmware_retraction",
|
||||
"use_relative_e_distances",
|
||||
"wipe_tower_type",
|
||||
"wrapping_detection_gcode",
|
||||
"wrapping_detection_layers",
|
||||
"wrapping_exclude_area",
|
||||
"z_hop_types",
|
||||
"z_offset",
|
||||
};
|
||||
5716
src/slic3r/GUI/generated/PrintConfigDef_generated.cpp
Normal file
5716
src/slic3r/GUI/generated/PrintConfigDef_generated.cpp
Normal file
File diff suppressed because it is too large
Load Diff
973
src/slic3r/GUI/generated/TabLayout_generated.cpp
Normal file
973
src/slic3r/GUI/generated/TabLayout_generated.cpp
Normal file
@@ -0,0 +1,973 @@
|
||||
// ===== AUTO-GENERATED by tools/config_codegen.py from layout.yaml =====
|
||||
// DO NOT EDIT MANUALLY. Edit layout.yaml and re-run: python tools/run_codegen.py
|
||||
//
|
||||
// Included inside namespace Slic3r::GUI in Tab.cpp after validate_custom_gcode_cb
|
||||
// forward declaration. No namespace wrapper needed here.
|
||||
|
||||
namespace { constexpr int gcode_field_height = 15; }
|
||||
namespace { constexpr int notes_field_height = 25; }
|
||||
|
||||
inline void TabPrint_build_quality_layout(TabPrint& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Quality"), "custom-gcode_quality");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Layer height"));
|
||||
optgroup->append_single_option_line("layer_height");
|
||||
optgroup->append_single_option_line("initial_layer_print_height");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Line width"));
|
||||
optgroup->append_single_option_line("line_width");
|
||||
optgroup->append_single_option_line("initial_layer_line_width");
|
||||
optgroup->append_single_option_line("outer_wall_line_width");
|
||||
optgroup->append_single_option_line("inner_wall_line_width");
|
||||
optgroup->append_single_option_line("top_surface_line_width");
|
||||
optgroup->append_single_option_line("sparse_infill_line_width");
|
||||
optgroup->append_single_option_line("internal_solid_infill_line_width");
|
||||
optgroup->append_single_option_line("support_line_width");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Seam"));
|
||||
optgroup->append_single_option_line("seam_position");
|
||||
optgroup->append_single_option_line("staggered_inner_seams");
|
||||
optgroup->append_single_option_line("seam_gap");
|
||||
optgroup->append_single_option_line("seam_slope_type");
|
||||
optgroup->append_single_option_line("seam_slope_conditional");
|
||||
optgroup->append_single_option_line("scarf_angle_threshold");
|
||||
optgroup->append_single_option_line("scarf_overhang_threshold");
|
||||
optgroup->append_single_option_line("scarf_joint_speed");
|
||||
optgroup->append_single_option_line("seam_slope_start_height");
|
||||
optgroup->append_single_option_line("seam_slope_entire_loop");
|
||||
optgroup->append_single_option_line("seam_slope_min_length");
|
||||
optgroup->append_single_option_line("seam_slope_steps");
|
||||
optgroup->append_single_option_line("scarf_joint_flow_ratio");
|
||||
optgroup->append_single_option_line("seam_slope_inner_walls");
|
||||
optgroup->append_single_option_line("role_based_wipe_speed");
|
||||
optgroup->append_single_option_line("wipe_speed");
|
||||
optgroup->append_single_option_line("wipe_on_loops");
|
||||
optgroup->append_single_option_line("wipe_before_external_loop");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Precision"));
|
||||
optgroup->append_single_option_line("slice_closing_radius");
|
||||
optgroup->append_single_option_line("resolution");
|
||||
optgroup->append_single_option_line("enable_arc_fitting");
|
||||
optgroup->append_single_option_line("xy_hole_compensation");
|
||||
optgroup->append_single_option_line("xy_contour_compensation");
|
||||
optgroup->append_single_option_line("elefant_foot_compensation");
|
||||
optgroup->append_single_option_line("elefant_foot_layers_density");
|
||||
optgroup->append_single_option_line("elefant_foot_compensation_layers");
|
||||
optgroup->append_single_option_line("precise_outer_wall");
|
||||
optgroup->append_single_option_line("precise_z_height");
|
||||
optgroup->append_single_option_line("hole_to_polyhole");
|
||||
optgroup->append_single_option_line("hole_to_polyhole_threshold");
|
||||
optgroup->append_single_option_line("hole_to_polyhole_twisted");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Ironing"));
|
||||
optgroup->append_single_option_line("ironing_type");
|
||||
optgroup->append_single_option_line("ironing_pattern");
|
||||
optgroup->append_single_option_line("ironing_flow");
|
||||
optgroup->append_single_option_line("ironing_spacing");
|
||||
optgroup->append_single_option_line("ironing_inset");
|
||||
optgroup->append_single_option_line("ironing_angle");
|
||||
optgroup->append_single_option_line("ironing_angle_fixed");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Wall generator"));
|
||||
optgroup->append_single_option_line("wall_generator");
|
||||
optgroup->append_single_option_line("wall_transition_angle");
|
||||
optgroup->append_single_option_line("wall_transition_filter_deviation");
|
||||
optgroup->append_single_option_line("wall_transition_length");
|
||||
optgroup->append_single_option_line("wall_distribution_count");
|
||||
optgroup->append_single_option_line("initial_layer_min_bead_width");
|
||||
optgroup->append_single_option_line("min_bead_width");
|
||||
optgroup->append_single_option_line("min_feature_size");
|
||||
optgroup->append_single_option_line("min_length_factor");
|
||||
optgroup->append_single_option_line("wall_maximum_resolution");
|
||||
optgroup->append_single_option_line("wall_maximum_deviation");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Walls and surfaces"));
|
||||
optgroup->append_single_option_line("wall_sequence");
|
||||
optgroup->append_single_option_line("is_infill_first");
|
||||
optgroup->append_single_option_line("wall_direction");
|
||||
optgroup->append_single_option_line("print_flow_ratio");
|
||||
optgroup->append_single_option_line("top_solid_infill_flow_ratio");
|
||||
optgroup->append_single_option_line("bottom_solid_infill_flow_ratio");
|
||||
optgroup->append_single_option_line("set_other_flow_ratios");
|
||||
optgroup->append_single_option_line("first_layer_flow_ratio");
|
||||
optgroup->append_single_option_line("outer_wall_flow_ratio");
|
||||
optgroup->append_single_option_line("inner_wall_flow_ratio");
|
||||
optgroup->append_single_option_line("overhang_flow_ratio");
|
||||
optgroup->append_single_option_line("sparse_infill_flow_ratio");
|
||||
optgroup->append_single_option_line("internal_solid_infill_flow_ratio");
|
||||
optgroup->append_single_option_line("gap_fill_flow_ratio");
|
||||
optgroup->append_single_option_line("support_flow_ratio");
|
||||
optgroup->append_single_option_line("support_interface_flow_ratio");
|
||||
optgroup->append_single_option_line("only_one_wall_first_layer");
|
||||
optgroup->append_single_option_line("only_one_wall_top");
|
||||
optgroup->append_single_option_line("min_width_top_surface");
|
||||
optgroup->append_single_option_line("reduce_crossing_wall");
|
||||
optgroup->append_single_option_line("max_travel_detour_distance");
|
||||
optgroup->append_single_option_line("small_area_infill_flow_compensation");
|
||||
optgroup->append_single_option_line("small_area_infill_flow_compensation_model");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Bridging"));
|
||||
optgroup->append_single_option_line("bridge_flow");
|
||||
optgroup->append_single_option_line("internal_bridge_flow");
|
||||
optgroup->append_single_option_line("bridge_density");
|
||||
optgroup->append_single_option_line("internal_bridge_density");
|
||||
optgroup->append_single_option_line("thick_bridges");
|
||||
optgroup->append_single_option_line("thick_internal_bridges");
|
||||
optgroup->append_single_option_line("enable_extra_bridge_layer");
|
||||
optgroup->append_single_option_line("dont_filter_internal_bridges");
|
||||
optgroup->append_single_option_line("counterbore_hole_bridging");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Overhangs"));
|
||||
optgroup->append_single_option_line("detect_overhang_wall");
|
||||
optgroup->append_single_option_line("make_overhang_printable");
|
||||
optgroup->append_single_option_line("make_overhang_printable_angle");
|
||||
optgroup->append_single_option_line("make_overhang_printable_hole_size");
|
||||
optgroup->append_single_option_line("extra_perimeters_on_overhangs");
|
||||
optgroup->append_single_option_line("overhang_reverse");
|
||||
optgroup->append_single_option_line("overhang_reverse_internal_only");
|
||||
optgroup->append_single_option_line("overhang_reverse_threshold");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabPrint_build_strength_layout(TabPrint& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Strength"), "custom-gcode_strength");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Walls"));
|
||||
optgroup->append_single_option_line("wall_loops");
|
||||
optgroup->append_single_option_line("alternate_extra_wall");
|
||||
optgroup->append_single_option_line("detect_thin_wall");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Top/bottom shells"));
|
||||
optgroup->append_single_option_line("top_shell_layers");
|
||||
optgroup->append_single_option_line("top_shell_thickness");
|
||||
optgroup->append_single_option_line("top_surface_density");
|
||||
optgroup->append_single_option_line("top_surface_pattern");
|
||||
optgroup->append_single_option_line("bottom_shell_layers");
|
||||
optgroup->append_single_option_line("bottom_shell_thickness");
|
||||
optgroup->append_single_option_line("bottom_surface_density");
|
||||
optgroup->append_single_option_line("bottom_surface_pattern");
|
||||
optgroup->append_single_option_line("top_bottom_infill_wall_overlap");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Infill"));
|
||||
optgroup->append_single_option_line("sparse_infill_density");
|
||||
optgroup->append_single_option_line("fill_multiline");
|
||||
optgroup->append_single_option_line("sparse_infill_pattern");
|
||||
optgroup->append_single_option_line("infill_direction");
|
||||
optgroup->append_single_option_line("sparse_infill_rotate_template");
|
||||
optgroup->append_single_option_line("skin_infill_density");
|
||||
optgroup->append_single_option_line("skeleton_infill_density");
|
||||
optgroup->append_single_option_line("infill_lock_depth");
|
||||
optgroup->append_single_option_line("skin_infill_depth");
|
||||
optgroup->append_single_option_line("skin_infill_line_width");
|
||||
optgroup->append_single_option_line("skeleton_infill_line_width");
|
||||
optgroup->append_single_option_line("symmetric_infill_y_axis");
|
||||
optgroup->append_single_option_line("infill_shift_step");
|
||||
optgroup->append_single_option_line("lateral_lattice_angle_1");
|
||||
optgroup->append_single_option_line("lateral_lattice_angle_2");
|
||||
optgroup->append_single_option_line("infill_overhang_angle");
|
||||
optgroup->append_single_option_line("infill_anchor_max");
|
||||
optgroup->append_single_option_line("infill_anchor");
|
||||
optgroup->append_single_option_line("internal_solid_infill_pattern");
|
||||
optgroup->append_single_option_line("solid_infill_direction");
|
||||
optgroup->append_single_option_line("solid_infill_rotate_template");
|
||||
optgroup->append_single_option_line("gap_fill_target");
|
||||
optgroup->append_single_option_line("filter_out_gap_fill");
|
||||
optgroup->append_single_option_line("infill_wall_overlap");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Advanced"));
|
||||
optgroup->append_single_option_line("align_infill_direction_to_model");
|
||||
optgroup->append_single_option_line("extra_solid_infills");
|
||||
optgroup->append_single_option_line("bridge_angle");
|
||||
optgroup->append_single_option_line("internal_bridge_angle");
|
||||
optgroup->append_single_option_line("minimum_sparse_infill_area");
|
||||
optgroup->append_single_option_line("infill_combination");
|
||||
optgroup->append_single_option_line("infill_combination_max_layer_height");
|
||||
optgroup->append_single_option_line("detect_narrow_internal_solid_infill");
|
||||
optgroup->append_single_option_line("ensure_vertical_shell_thickness");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabPrint_build_speed_layout(TabPrint& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Speed"), "custom-gcode_speed");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("First layer speed"));
|
||||
optgroup->append_single_option_line("initial_layer_speed");
|
||||
optgroup->append_single_option_line("initial_layer_infill_speed");
|
||||
optgroup->append_single_option_line("initial_layer_travel_speed");
|
||||
optgroup->append_single_option_line("slow_down_layers");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Other layers speed"));
|
||||
optgroup->append_single_option_line("outer_wall_speed");
|
||||
optgroup->append_single_option_line("inner_wall_speed");
|
||||
optgroup->append_single_option_line("small_perimeter_speed");
|
||||
optgroup->append_single_option_line("small_perimeter_threshold");
|
||||
optgroup->append_single_option_line("sparse_infill_speed");
|
||||
optgroup->append_single_option_line("internal_solid_infill_speed");
|
||||
optgroup->append_single_option_line("top_surface_speed");
|
||||
optgroup->append_single_option_line("gap_infill_speed");
|
||||
optgroup->append_single_option_line("ironing_speed");
|
||||
optgroup->append_single_option_line("support_speed");
|
||||
optgroup->append_single_option_line("support_interface_speed");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Overhang speed"));
|
||||
optgroup->append_single_option_line("enable_overhang_speed");
|
||||
optgroup->append_single_option_line("slowdown_for_curled_perimeters");
|
||||
{
|
||||
Line line_{optgroup->get_option("overhang_1_4_speed").opt.label, optgroup->get_option("overhang_1_4_speed").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("overhang_1_4_speed"));
|
||||
line_.append_option(optgroup->get_option("overhang_2_4_speed"));
|
||||
line_.append_option(optgroup->get_option("overhang_3_4_speed"));
|
||||
line_.append_option(optgroup->get_option("overhang_4_4_speed"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
{
|
||||
Line line_{optgroup->get_option("bridge_speed").opt.label, optgroup->get_option("bridge_speed").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("bridge_speed"));
|
||||
line_.append_option(optgroup->get_option("internal_bridge_speed"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Travel speed"));
|
||||
optgroup->append_single_option_line("travel_speed");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Acceleration"));
|
||||
optgroup->append_single_option_line("default_acceleration");
|
||||
optgroup->append_single_option_line("outer_wall_acceleration");
|
||||
optgroup->append_single_option_line("inner_wall_acceleration");
|
||||
optgroup->append_single_option_line("bridge_acceleration");
|
||||
optgroup->append_single_option_line("sparse_infill_acceleration");
|
||||
optgroup->append_single_option_line("internal_solid_infill_acceleration");
|
||||
optgroup->append_single_option_line("initial_layer_acceleration");
|
||||
optgroup->append_single_option_line("initial_layer_travel_acceleration");
|
||||
optgroup->append_single_option_line("top_surface_acceleration");
|
||||
optgroup->append_single_option_line("travel_acceleration");
|
||||
optgroup->append_single_option_line("accel_to_decel_enable");
|
||||
optgroup->append_single_option_line("accel_to_decel_factor");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Jerk(XY)"));
|
||||
optgroup->append_single_option_line("default_junction_deviation");
|
||||
optgroup->append_single_option_line("default_jerk");
|
||||
optgroup->append_single_option_line("outer_wall_jerk");
|
||||
optgroup->append_single_option_line("inner_wall_jerk");
|
||||
optgroup->append_single_option_line("infill_jerk");
|
||||
optgroup->append_single_option_line("top_surface_jerk");
|
||||
optgroup->append_single_option_line("initial_layer_jerk");
|
||||
optgroup->append_single_option_line("initial_layer_travel_jerk");
|
||||
optgroup->append_single_option_line("travel_jerk");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Advanced"));
|
||||
optgroup->append_single_option_line("max_volumetric_extrusion_rate_slope");
|
||||
optgroup->append_single_option_line("max_volumetric_extrusion_rate_slope_segment_length");
|
||||
optgroup->append_single_option_line("extrusion_rate_smoothing_external_perimeter_only");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabPrint_build_support_layout(TabPrint& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Support"), "custom-gcode_support");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Support"));
|
||||
optgroup->append_single_option_line("enable_support");
|
||||
optgroup->append_single_option_line("support_type");
|
||||
optgroup->append_single_option_line("support_style");
|
||||
optgroup->append_single_option_line("support_threshold_angle");
|
||||
optgroup->append_single_option_line("support_threshold_overlap");
|
||||
optgroup->append_single_option_line("raft_first_layer_density");
|
||||
optgroup->append_single_option_line("raft_first_layer_expansion");
|
||||
optgroup->append_single_option_line("support_on_build_plate_only");
|
||||
optgroup->append_single_option_line("support_critical_regions_only");
|
||||
optgroup->append_single_option_line("support_remove_small_overhang");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Raft"));
|
||||
optgroup->append_single_option_line("raft_layers");
|
||||
optgroup->append_single_option_line("raft_contact_distance");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Support filament"));
|
||||
optgroup->append_single_option_line("support_filament");
|
||||
optgroup->append_single_option_line("support_interface_filament");
|
||||
optgroup->append_single_option_line("support_interface_not_for_body");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Support ironing"));
|
||||
optgroup->append_single_option_line("support_ironing");
|
||||
optgroup->append_single_option_line("support_ironing_pattern");
|
||||
optgroup->append_single_option_line("support_ironing_flow");
|
||||
optgroup->append_single_option_line("support_ironing_spacing");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Advanced"));
|
||||
optgroup->append_single_option_line("support_top_z_distance");
|
||||
optgroup->append_single_option_line("support_bottom_z_distance");
|
||||
optgroup->append_single_option_line("tree_support_wall_count");
|
||||
optgroup->append_single_option_line("support_base_pattern");
|
||||
optgroup->append_single_option_line("support_base_pattern_spacing");
|
||||
optgroup->append_single_option_line("support_angle");
|
||||
optgroup->append_single_option_line("support_interface_top_layers");
|
||||
optgroup->append_single_option_line("support_interface_bottom_layers");
|
||||
optgroup->append_single_option_line("support_interface_pattern");
|
||||
optgroup->append_single_option_line("support_interface_spacing");
|
||||
optgroup->append_single_option_line("support_bottom_interface_spacing");
|
||||
optgroup->append_single_option_line("support_expansion");
|
||||
optgroup->append_single_option_line("support_object_xy_distance");
|
||||
optgroup->append_single_option_line("support_object_first_layer_gap");
|
||||
optgroup->append_single_option_line("bridge_no_support");
|
||||
optgroup->append_single_option_line("max_bridge_length");
|
||||
optgroup->append_single_option_line("independent_support_layer_height");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Tree supports"));
|
||||
optgroup->append_single_option_line("tree_support_tip_diameter");
|
||||
optgroup->append_single_option_line("tree_support_branch_distance");
|
||||
optgroup->append_single_option_line("tree_support_branch_distance_organic");
|
||||
optgroup->append_single_option_line("tree_support_top_rate");
|
||||
optgroup->append_single_option_line("tree_support_branch_diameter");
|
||||
optgroup->append_single_option_line("tree_support_branch_diameter_organic");
|
||||
optgroup->append_single_option_line("tree_support_branch_diameter_angle");
|
||||
optgroup->append_single_option_line("tree_support_branch_angle");
|
||||
optgroup->append_single_option_line("tree_support_branch_angle_organic");
|
||||
optgroup->append_single_option_line("tree_support_angle_slow");
|
||||
optgroup->append_single_option_line("tree_support_auto_brim");
|
||||
optgroup->append_single_option_line("tree_support_brim_width");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabPrint_build_multimaterial_layout(TabPrint& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Multimaterial"), "custom-gcode_multi_material");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Prime tower"));
|
||||
optgroup->append_single_option_line("enable_prime_tower");
|
||||
optgroup->append_single_option_line("prime_tower_skip_points");
|
||||
optgroup->append_single_option_line("enable_tower_interface_features");
|
||||
optgroup->append_single_option_line("enable_tower_interface_cooldown_during_tower");
|
||||
optgroup->append_single_option_line("prime_tower_enable_framework");
|
||||
optgroup->append_single_option_line("prime_tower_width");
|
||||
optgroup->append_single_option_line("prime_volume");
|
||||
optgroup->append_single_option_line("prime_tower_brim_width");
|
||||
optgroup->append_single_option_line("prime_tower_infill_gap");
|
||||
optgroup->append_single_option_line("wipe_tower_rotation_angle");
|
||||
optgroup->append_single_option_line("wipe_tower_bridging");
|
||||
optgroup->append_single_option_line("wipe_tower_extra_spacing");
|
||||
optgroup->append_single_option_line("wipe_tower_extra_flow");
|
||||
optgroup->append_single_option_line("wipe_tower_max_purge_speed");
|
||||
optgroup->append_single_option_line("wipe_tower_wall_type");
|
||||
optgroup->append_single_option_line("wipe_tower_cone_angle");
|
||||
optgroup->append_single_option_line("wipe_tower_extra_rib_length");
|
||||
optgroup->append_single_option_line("wipe_tower_rib_width");
|
||||
optgroup->append_single_option_line("wipe_tower_fillet_wall");
|
||||
optgroup->append_single_option_line("wipe_tower_no_sparse_layers");
|
||||
optgroup->append_single_option_line("single_extruder_multi_material_priming");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Filament for Features"));
|
||||
optgroup->append_single_option_line("wall_filament");
|
||||
optgroup->append_single_option_line("sparse_infill_filament");
|
||||
optgroup->append_single_option_line("solid_infill_filament");
|
||||
optgroup->append_single_option_line("wipe_tower_filament");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Ooze prevention"));
|
||||
optgroup->append_single_option_line("ooze_prevention");
|
||||
optgroup->append_single_option_line("standby_temperature_delta");
|
||||
optgroup->append_single_option_line("preheat_time");
|
||||
optgroup->append_single_option_line("preheat_steps");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Flush options"));
|
||||
optgroup->append_single_option_line("flush_into_infill");
|
||||
optgroup->append_single_option_line("flush_into_objects");
|
||||
optgroup->append_single_option_line("flush_into_support");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Advanced"));
|
||||
optgroup->append_single_option_line("interlocking_beam");
|
||||
optgroup->append_single_option_line("interface_shells");
|
||||
optgroup->append_single_option_line("mmu_segmented_region_max_width");
|
||||
optgroup->append_single_option_line("mmu_segmented_region_interlocking_depth");
|
||||
optgroup->append_single_option_line("interlocking_beam_width");
|
||||
optgroup->append_single_option_line("interlocking_orientation");
|
||||
optgroup->append_single_option_line("interlocking_beam_layer_count");
|
||||
optgroup->append_single_option_line("interlocking_depth");
|
||||
optgroup->append_single_option_line("interlocking_boundary_avoidance");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabPrint_build_others_layout(TabPrint& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Others"), "custom-gcode_other");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Skirt"));
|
||||
optgroup->append_single_option_line("skirt_loops");
|
||||
optgroup->append_single_option_line("skirt_type");
|
||||
optgroup->append_single_option_line("min_skirt_length");
|
||||
optgroup->append_single_option_line("skirt_distance");
|
||||
optgroup->append_single_option_line("skirt_start_angle");
|
||||
optgroup->append_single_option_line("skirt_speed");
|
||||
optgroup->append_single_option_line("skirt_height");
|
||||
optgroup->append_single_option_line("draft_shield");
|
||||
optgroup->append_single_option_line("single_loop_draft_shield");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Brim"));
|
||||
optgroup->append_single_option_line("brim_type");
|
||||
optgroup->append_single_option_line("brim_width");
|
||||
optgroup->append_single_option_line("brim_object_gap");
|
||||
optgroup->append_single_option_line("brim_flow_ratio");
|
||||
optgroup->append_single_option_line("brim_use_efc_outline");
|
||||
optgroup->append_single_option_line("combine_brims");
|
||||
optgroup->append_single_option_line("brim_ears_max_angle");
|
||||
optgroup->append_single_option_line("brim_ears_detection_length");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Special mode"));
|
||||
optgroup->append_single_option_line("slicing_mode");
|
||||
optgroup->append_single_option_line("print_sequence");
|
||||
optgroup->append_single_option_line("print_order");
|
||||
optgroup->append_single_option_line("spiral_mode");
|
||||
optgroup->append_single_option_line("spiral_mode_smooth");
|
||||
optgroup->append_single_option_line("spiral_mode_max_xy_smoothing");
|
||||
optgroup->append_single_option_line("spiral_starting_flow_ratio");
|
||||
optgroup->append_single_option_line("spiral_finishing_flow_ratio");
|
||||
optgroup->append_single_option_line("timelapse_type");
|
||||
optgroup->append_single_option_line("enable_wrapping_detection");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Fuzzy Skin"));
|
||||
optgroup->append_single_option_line("fuzzy_skin");
|
||||
optgroup->append_single_option_line("fuzzy_skin_mode");
|
||||
optgroup->append_single_option_line("fuzzy_skin_noise_type");
|
||||
optgroup->append_single_option_line("fuzzy_skin_point_distance");
|
||||
optgroup->append_single_option_line("fuzzy_skin_thickness");
|
||||
optgroup->append_single_option_line("fuzzy_skin_scale");
|
||||
optgroup->append_single_option_line("fuzzy_skin_octaves");
|
||||
optgroup->append_single_option_line("fuzzy_skin_persistence");
|
||||
optgroup->append_single_option_line("fuzzy_skin_first_layer");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("G-code output"));
|
||||
optgroup->append_single_option_line("reduce_infill_retraction");
|
||||
optgroup->append_single_option_line("gcode_add_line_number");
|
||||
optgroup->append_single_option_line("gcode_comments");
|
||||
optgroup->append_single_option_line("gcode_label_objects");
|
||||
optgroup->append_single_option_line("exclude_object");
|
||||
optgroup->append_single_option_line("filename_format");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Change extrusion role G-code"));
|
||||
optgroup->append_single_option_line("process_change_extrusion_role_gcode");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Post-processing Scripts"));
|
||||
optgroup->append_single_option_line("post_process");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Notes"));
|
||||
optgroup->append_single_option_line("notes");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabFilament_build_filament_layout(TabFilament& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Filament"), "custom-gcode_filament");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Basic information"));
|
||||
optgroup->append_single_option_line("filament_type");
|
||||
optgroup->append_single_option_line("filament_vendor");
|
||||
optgroup->append_single_option_line("filament_soluble");
|
||||
optgroup->append_single_option_line("filament_is_support");
|
||||
optgroup->append_single_option_line("filament_change_length");
|
||||
optgroup->append_single_option_line("required_nozzle_HRC");
|
||||
optgroup->append_single_option_line("default_filament_colour");
|
||||
optgroup->append_single_option_line("filament_diameter");
|
||||
optgroup->append_single_option_line("filament_adhesiveness_category");
|
||||
optgroup->append_single_option_line("filament_density");
|
||||
optgroup->append_single_option_line("filament_shrink");
|
||||
optgroup->append_single_option_line("filament_shrinkage_compensation_z");
|
||||
optgroup->append_single_option_line("filament_cost");
|
||||
optgroup->append_single_option_line("temperature_vitrification");
|
||||
optgroup->append_single_option_line("idle_temperature");
|
||||
{
|
||||
Line line_{optgroup->get_option("nozzle_temperature_range_low").opt.label, optgroup->get_option("nozzle_temperature_range_low").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("nozzle_temperature_range_low"));
|
||||
line_.append_option(optgroup->get_option("nozzle_temperature_range_high"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Flow ratio and Pressure Advance"));
|
||||
optgroup->append_single_option_line("pellet_flow_coefficient");
|
||||
optgroup->append_single_option_line("filament_flow_ratio");
|
||||
optgroup->append_single_option_line("enable_pressure_advance");
|
||||
optgroup->append_single_option_line("pressure_advance");
|
||||
optgroup->append_single_option_line("adaptive_pressure_advance");
|
||||
optgroup->append_single_option_line("adaptive_pressure_advance_overhangs");
|
||||
optgroup->append_single_option_line("adaptive_pressure_advance_bridges");
|
||||
optgroup->append_single_option_line("adaptive_pressure_advance_model");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Print chamber temperature"));
|
||||
optgroup->append_single_option_line("activate_chamber_temp_control");
|
||||
optgroup->append_single_option_line("chamber_temperature");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Print temperature"));
|
||||
{
|
||||
Line line_{optgroup->get_option("nozzle_temperature_initial_layer").opt.label, optgroup->get_option("nozzle_temperature_initial_layer").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("nozzle_temperature_initial_layer"));
|
||||
line_.append_option(optgroup->get_option("nozzle_temperature"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Bed temperature"));
|
||||
{
|
||||
Line line_{optgroup->get_option("supertack_plate_temp_initial_layer").opt.label, optgroup->get_option("supertack_plate_temp_initial_layer").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("supertack_plate_temp_initial_layer"));
|
||||
line_.append_option(optgroup->get_option("supertack_plate_temp"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
{
|
||||
Line line_{optgroup->get_option("cool_plate_temp_initial_layer").opt.label, optgroup->get_option("cool_plate_temp_initial_layer").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("cool_plate_temp_initial_layer"));
|
||||
line_.append_option(optgroup->get_option("cool_plate_temp"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
{
|
||||
Line line_{optgroup->get_option("textured_cool_plate_temp_initial_layer").opt.label, optgroup->get_option("textured_cool_plate_temp_initial_layer").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("textured_cool_plate_temp_initial_layer"));
|
||||
line_.append_option(optgroup->get_option("textured_cool_plate_temp"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
{
|
||||
Line line_{optgroup->get_option("eng_plate_temp_initial_layer").opt.label, optgroup->get_option("eng_plate_temp_initial_layer").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("eng_plate_temp_initial_layer"));
|
||||
line_.append_option(optgroup->get_option("eng_plate_temp"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
{
|
||||
Line line_{optgroup->get_option("hot_plate_temp_initial_layer").opt.label, optgroup->get_option("hot_plate_temp_initial_layer").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("hot_plate_temp_initial_layer"));
|
||||
line_.append_option(optgroup->get_option("hot_plate_temp"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
{
|
||||
Line line_{optgroup->get_option("textured_plate_temp_initial_layer").opt.label, optgroup->get_option("textured_plate_temp_initial_layer").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("textured_plate_temp_initial_layer"));
|
||||
line_.append_option(optgroup->get_option("textured_plate_temp"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Volumetric speed limitation"));
|
||||
optgroup->append_single_option_line("filament_adaptive_volumetric_speed");
|
||||
optgroup->append_single_option_line("filament_max_volumetric_speed");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabFilament_build_cooling_layout(TabFilament& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Cooling"), "custom-gcode_cooling_fan");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Cooling for specific layer"));
|
||||
optgroup->append_single_option_line("close_fan_the_first_x_layers");
|
||||
optgroup->append_single_option_line("full_fan_speed_layer");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Part cooling fan"));
|
||||
{
|
||||
Line line_{optgroup->get_option("fan_min_speed").opt.label, optgroup->get_option("fan_min_speed").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("fan_min_speed"));
|
||||
line_.append_option(optgroup->get_option("fan_cooling_layer_time"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
{
|
||||
Line line_{optgroup->get_option("fan_max_speed").opt.label, optgroup->get_option("fan_max_speed").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("fan_max_speed"));
|
||||
line_.append_option(optgroup->get_option("slow_down_layer_time"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
optgroup->append_single_option_line("reduce_fan_stop_start_freq");
|
||||
optgroup->append_single_option_line("slow_down_for_layer_cooling");
|
||||
optgroup->append_single_option_line("dont_slow_down_outer_wall");
|
||||
optgroup->append_single_option_line("slow_down_min_speed");
|
||||
optgroup->append_single_option_line("enable_overhang_bridge_fan");
|
||||
optgroup->append_single_option_line("overhang_fan_threshold");
|
||||
optgroup->append_single_option_line("overhang_fan_speed");
|
||||
optgroup->append_single_option_line("internal_bridge_fan_speed");
|
||||
optgroup->append_single_option_line("support_material_interface_fan_speed");
|
||||
optgroup->append_single_option_line("ironing_fan_speed");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Auxiliary part cooling fan"));
|
||||
optgroup->append_single_option_line("additional_cooling_fan_speed");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Exhaust fan"));
|
||||
optgroup->append_single_option_line("activate_air_filtration");
|
||||
{
|
||||
Line line_{optgroup->get_option("activate_air_filtration_during_print").opt.label, optgroup->get_option("activate_air_filtration_during_print").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("activate_air_filtration_during_print"));
|
||||
line_.append_option(optgroup->get_option("during_print_exhaust_fan_speed"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
{
|
||||
Line line_{optgroup->get_option("activate_air_filtration_on_completion").opt.label, optgroup->get_option("activate_air_filtration_on_completion").opt.tooltip};
|
||||
line_.append_option(optgroup->get_option("activate_air_filtration_on_completion"));
|
||||
line_.append_option(optgroup->get_option("complete_print_exhaust_fan_speed"));
|
||||
optgroup->append_line(line_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabFilament_build_advanced_layout(TabFilament& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Advanced"), "custom-gcode_advanced");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Filament start G-code"));
|
||||
optgroup->append_single_option_line("filament_start_gcode");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Change extrusion role G-code"));
|
||||
optgroup->append_single_option_line("filament_change_extrusion_role_gcode");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Filament end G-code"));
|
||||
optgroup->append_single_option_line("filament_end_gcode");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabFilament_build_multimaterial_layout(TabFilament& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Multimaterial"), "custom-gcode_multi_material");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Wipe tower parameters"));
|
||||
optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower");
|
||||
optgroup->append_single_option_line("filament_tower_interface_pre_extrusion_dist");
|
||||
optgroup->append_single_option_line("filament_tower_interface_pre_extrusion_length");
|
||||
optgroup->append_single_option_line("filament_tower_ironing_area");
|
||||
optgroup->append_single_option_line("filament_tower_interface_purge_volume");
|
||||
optgroup->append_single_option_line("filament_tower_interface_print_temp");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Multi Filament"));
|
||||
optgroup->append_single_option_line("long_retractions_when_ec");
|
||||
optgroup->append_single_option_line("retraction_distances_when_ec");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Tool change parameters with single extruder MM printers"));
|
||||
optgroup->append_single_option_line("filament_loading_speed_start");
|
||||
optgroup->append_single_option_line("filament_loading_speed");
|
||||
optgroup->append_single_option_line("filament_unloading_speed_start");
|
||||
optgroup->append_single_option_line("filament_unloading_speed");
|
||||
optgroup->append_single_option_line("filament_toolchange_delay");
|
||||
optgroup->append_single_option_line("filament_cooling_moves");
|
||||
optgroup->append_single_option_line("filament_cooling_initial_speed");
|
||||
optgroup->append_single_option_line("filament_cooling_final_speed");
|
||||
optgroup->append_single_option_line("filament_stamping_loading_speed");
|
||||
optgroup->append_single_option_line("filament_stamping_distance");
|
||||
optgroup->append_single_option_line("filament_ramming_parameters");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Tool change parameters with multi extruder MM printers"));
|
||||
optgroup->append_single_option_line("filament_multitool_ramming");
|
||||
optgroup->append_single_option_line("filament_multitool_ramming_volume");
|
||||
optgroup->append_single_option_line("filament_multitool_ramming_flow");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabFilament_build_dependencies_layout(TabFilament& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Dependencies"), "advanced");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Compatible printers"));
|
||||
optgroup->append_single_option_line("compatible_printers");
|
||||
optgroup->append_single_option_line("compatible_printers_condition");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Compatible process profiles"));
|
||||
optgroup->append_single_option_line("compatible_prints");
|
||||
optgroup->append_single_option_line("compatible_prints_condition");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabFilament_build_notes_layout(TabFilament& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Notes"), "custom-gcode_note");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Notes"));
|
||||
optgroup->append_single_option_line("filament_notes");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabPrinter_build_basic_information_layout(TabPrinter& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Basic information"), "custom-gcode_object-info");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Printable space"), L"param_printable_space");
|
||||
tab.layout_hook_printable_space(optgroup.get());
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Advanced"), L"param_advanced");
|
||||
tab.layout_hook_advanced(optgroup.get());
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Cooling Fan"), L"param_cooling_fan");
|
||||
tab.layout_hook_cooling_fan(optgroup.get());
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Extruder Clearance"), L"param_extruder_clearance");
|
||||
optgroup->append_single_option_line("extruder_clearance_radius", "printer_basic_information_extruder_clearance#radius");
|
||||
optgroup->append_single_option_line("extruder_clearance_height_to_rod", "printer_basic_information_extruder_clearance#height-to-rod");
|
||||
optgroup->append_single_option_line("extruder_clearance_height_to_lid", "printer_basic_information_extruder_clearance#height-to-lid");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Adaptive bed mesh"), L"param_adaptive_mesh");
|
||||
optgroup->append_single_option_line("bed_mesh_min", "printer_basic_information_adaptive_bed_mesh#bed-mesh");
|
||||
optgroup->append_single_option_line("bed_mesh_max", "printer_basic_information_adaptive_bed_mesh#bed-mesh");
|
||||
optgroup->append_single_option_line("bed_mesh_probe_distance", "printer_basic_information_adaptive_bed_mesh#probe-point-distance");
|
||||
optgroup->append_single_option_line("adaptive_bed_mesh_margin", "printer_basic_information_adaptive_bed_mesh#mesh-margin");
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Accessory"), L"param_accessory");
|
||||
optgroup->append_single_option_line("nozzle_type", "printer_basic_information_accessory#nozzle-type");
|
||||
optgroup->append_single_option_line("nozzle_hrc", "printer_basic_information_accessory#nozzle-hrc");
|
||||
optgroup->append_single_option_line("auxiliary_fan", "printer_basic_information_accessory#auxiliary-part-cooling-fan");
|
||||
optgroup->append_single_option_line("support_chamber_temp_control", "printer_basic_information_accessory#support-controlling-chamber-temperature");
|
||||
optgroup->append_single_option_line("support_air_filtration", "printer_basic_information_accessory#support-air-filtration");
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabPrinter_build_machine_g_code_layout(TabPrinter& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Machine G-code"), "custom-gcode_gcode");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("File header G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("file_start_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option);
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Machine start G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("machine_start_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#machine-start-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Machine end G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("machine_end_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#machine-end-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Printing by object G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("printing_by_object_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#between-object-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Before layer change G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("before_layer_change_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#before-layer-change-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Layer change G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("layer_change_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#after-layer-change-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Timelapse G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("time_lapse_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#time-lapse-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Clumping Detection G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("wrapping_detection_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#clumping-detection-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Change filament G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("change_filament_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#change-filament-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Change extrusion role G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("change_extrusion_role_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#change-extrusion-role-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Pause G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("machine_pause_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#pause-g-code");
|
||||
}
|
||||
}
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Template Custom G-code"), L"param_gcode", 0);
|
||||
optgroup->m_on_change = [&tab, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
|
||||
validate_custom_gcode_cb(&tab, optgroup_title, opt_key, value);
|
||||
};
|
||||
optgroup->edit_custom_gcode = [&tab](const t_config_option_key& opt_key) { tab.edit_custom_gcode(opt_key); };
|
||||
{
|
||||
Option option = optgroup->get_option("template_custom_gcode");
|
||||
option.opt.full_width = true;
|
||||
option.opt.is_code = true;
|
||||
option.opt.height = gcode_field_height;
|
||||
optgroup->append_single_option_line(option, "printer_machine_gcode#template-custom-g-code");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void TabPrinter_build_notes_layout(TabPrinter& tab)
|
||||
{
|
||||
PageShp page = tab.add_options_page(L("Notes"), "custom-gcode_note");
|
||||
{
|
||||
auto optgroup = page->new_optgroup(L("Notes"), L"note");
|
||||
optgroup->append_single_option_line("printer_notes");
|
||||
}
|
||||
}
|
||||
|
||||
// ── Aggregate wrappers (backward-compatible with Tab.cpp call sites) ──
|
||||
|
||||
inline void TabPrint_build_layout(TabPrint& tab)
|
||||
{
|
||||
TabPrint_build_quality_layout(tab);
|
||||
TabPrint_build_strength_layout(tab);
|
||||
TabPrint_build_speed_layout(tab);
|
||||
TabPrint_build_support_layout(tab);
|
||||
TabPrint_build_multimaterial_layout(tab);
|
||||
TabPrint_build_others_layout(tab);
|
||||
}
|
||||
|
||||
inline void TabFilament_build_main_layout(TabFilament& tab)
|
||||
{
|
||||
TabFilament_build_filament_layout(tab);
|
||||
TabFilament_build_cooling_layout(tab);
|
||||
TabFilament_build_multimaterial_layout(tab);
|
||||
}
|
||||
|
||||
inline void TabPrinter_build_basic_info_layout(TabPrinter& tab)
|
||||
{
|
||||
TabPrinter_build_basic_information_layout(tab);
|
||||
}
|
||||
|
||||
inline void TabPrinter_build_gcode_layout(TabPrinter& tab)
|
||||
{
|
||||
TabPrinter_build_machine_g_code_layout(tab);
|
||||
TabPrinter_build_notes_layout(tab);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ add_executable(${_TEST_NAME}_tests
|
||||
test_optimizers.cpp
|
||||
# test_png_io.cpp
|
||||
test_indexed_triangle_set.cpp
|
||||
test_texture_displacement.cpp
|
||||
../libnest2d/printer_parts.cpp
|
||||
)
|
||||
|
||||
|
||||
136
tests/libslic3r/test_texture_displacement.cpp
Normal file
136
tests/libslic3r/test_texture_displacement.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#define NOMINMAX
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "libslic3r/TextureDisplacement.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
#include "libslic3r/TriangleSelector.hpp"
|
||||
#include "libslic3r/PNGReadWrite.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
using Catch::Matchers::WithinAbs;
|
||||
|
||||
// Encodes a flat (uniform-value) grayscale image through Slic3r's own PNG writer/reader round
|
||||
// trip, so decode_height_texture() (which only accepts true 8-bit grayscale PNG) is guaranteed a
|
||||
// compatible file, exactly like the GUI's "Add texture" import path does.
|
||||
static std::shared_ptr<std::vector<unsigned char>> make_flat_gray_png(uint8_t value, size_t w = 4, size_t h = 4)
|
||||
{
|
||||
std::vector<uint8_t> pixels(w * h, value);
|
||||
const boost::filesystem::path tmp_path = boost::filesystem::temp_directory_path()
|
||||
/ boost::filesystem::unique_path("texdisp_test_%%%%%%%%.png");
|
||||
REQUIRE(Slic3r::png::write_gray_to_file(tmp_path.string(), w, h, pixels));
|
||||
|
||||
std::vector<unsigned char> bytes;
|
||||
{
|
||||
std::ifstream ifs(tmp_path.string(), std::ios::binary);
|
||||
bytes.assign(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());
|
||||
}
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::remove(tmp_path, ec);
|
||||
|
||||
REQUIRE_FALSE(bytes.empty());
|
||||
return std::make_shared<std::vector<unsigned char>>(std::move(bytes));
|
||||
}
|
||||
|
||||
TEST_CASE("TextureDisplacement: decode_height_texture round-trips an 8-bit grayscale PNG", "[TextureDisplacement]")
|
||||
{
|
||||
TextureDisplacementLayer layer;
|
||||
layer.image_data = make_flat_gray_png(128, 4, 4);
|
||||
|
||||
DecodedHeightTexture tex = decode_height_texture(layer);
|
||||
REQUIRE_FALSE(tex.empty());
|
||||
CHECK(tex.width == 4);
|
||||
CHECK(tex.height == 4);
|
||||
REQUIRE_THAT(tex.sample(Vec2f(0.5f, 0.5f)), WithinAbs(128.0 / 255.0, 1.0 / 255.0));
|
||||
}
|
||||
|
||||
TEST_CASE("TextureDisplacement: an empty layer list leaves the mesh unchanged", "[TextureDisplacement]")
|
||||
{
|
||||
const indexed_triangle_set cube = its_make_cube(10., 10., 10.);
|
||||
const std::vector<TextureDisplacementLayer> layers; // none
|
||||
TextureDisplacementFacetsData facets{}; // all empty
|
||||
|
||||
const indexed_triangle_set result = build_texture_displacement(cube, layers, facets);
|
||||
|
||||
REQUIRE(result.vertices.size() == cube.vertices.size());
|
||||
REQUIRE(result.indices.size() == cube.indices.size());
|
||||
for (size_t i = 0; i < cube.vertices.size(); ++i)
|
||||
for (int c = 0; c < 3; ++c)
|
||||
CHECK(result.vertices[i](c) == cube.vertices[i](c));
|
||||
}
|
||||
|
||||
TEST_CASE("TextureDisplacement: fully painting a mesh displaces every vertex along its own normal", "[TextureDisplacement]")
|
||||
{
|
||||
const indexed_triangle_set cube = its_make_cube(10., 10., 10.);
|
||||
const TriangleMesh cube_mesh(cube);
|
||||
|
||||
TriangleSelector selector(cube_mesh);
|
||||
for (int f = 0; f < int(cube.indices.size()); ++f)
|
||||
selector.set_facet(f, EnforcerBlockerType::ENFORCER);
|
||||
|
||||
TextureDisplacementFacetsData facets{};
|
||||
facets[0] = selector.serialize();
|
||||
|
||||
TextureDisplacementLayer layer;
|
||||
layer.slot = 0;
|
||||
layer.depth_mm = 2.0f;
|
||||
layer.tiling_scale = 5.0f;
|
||||
layer.image_data = make_flat_gray_png(255); // sample() == 1.0 everywhere -> full depth_mm displacement
|
||||
|
||||
const indexed_triangle_set result = build_texture_displacement(cube, {layer}, facets);
|
||||
|
||||
REQUIRE(result.vertices.size() == cube.vertices.size());
|
||||
for (size_t i = 0; i < cube.vertices.size(); ++i) {
|
||||
const float moved = (result.vertices[i] - cube.vertices[i]).norm();
|
||||
CHECK_THAT(moved, WithinAbs(layer.depth_mm, 1e-3f));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("TextureDisplacement: boundary vertices shared with unpainted triangles are pinned", "[TextureDisplacement]")
|
||||
{
|
||||
// A small triangle fan around a central vertex O, with 4 outer points A/B/C/D forming 4
|
||||
// triangles T0..T3 in the XY plane. Only T0, T1, T2 are painted, T3 is left unpainted:
|
||||
// O: touches all 4 triangles (incl. unpainted T3) -> boundary, must NOT move
|
||||
// A: touches T0 (painted) and T3 (unpainted) -> boundary, must NOT move
|
||||
// D: touches T2 (painted) and T3 (unpainted) -> boundary, must NOT move
|
||||
// B: touches only T0 and T1 (both painted) -> interior, SHOULD move
|
||||
// C: touches only T1 and T2 (both painted) -> interior, SHOULD move
|
||||
indexed_triangle_set fan;
|
||||
fan.vertices = { {0.f, 0.f, 0.f}, {1.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {-1.f, 0.f, 0.f}, {0.f, -1.f, 0.f} };
|
||||
fan.indices = { {0, 1, 2}, {0, 2, 3}, {0, 3, 4}, {0, 4, 1} };
|
||||
|
||||
const TriangleMesh fan_mesh(fan);
|
||||
TriangleSelector selector(fan_mesh);
|
||||
selector.set_facet(0, EnforcerBlockerType::ENFORCER);
|
||||
selector.set_facet(1, EnforcerBlockerType::ENFORCER);
|
||||
selector.set_facet(2, EnforcerBlockerType::ENFORCER);
|
||||
// facet 3 (T3) is left at its default EnforcerBlockerType::NONE.
|
||||
|
||||
TextureDisplacementFacetsData facets{};
|
||||
facets[0] = selector.serialize();
|
||||
|
||||
TextureDisplacementLayer layer;
|
||||
layer.slot = 0;
|
||||
layer.depth_mm = 1.0f;
|
||||
layer.tiling_scale = 5.0f;
|
||||
layer.image_data = make_flat_gray_png(255);
|
||||
|
||||
const indexed_triangle_set result = build_texture_displacement(fan, {layer}, facets);
|
||||
|
||||
// Find each named vertex's post-bake position by matching the original (pinned vertices keep
|
||||
// their exact original position; moved ones won't match any original position anymore).
|
||||
auto still_at_original_position = [&](const Vec3f &original) {
|
||||
for (const Vec3f &v : result.vertices)
|
||||
if ((v - original).norm() < 1e-6f)
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
CHECK(still_at_original_position(fan.vertices[0])); // O: boundary
|
||||
CHECK(still_at_original_position(fan.vertices[1])); // A: boundary
|
||||
CHECK(still_at_original_position(fan.vertices[4])); // D: boundary
|
||||
CHECK_FALSE(still_at_original_position(fan.vertices[2])); // B: interior, must have moved
|
||||
CHECK_FALSE(still_at_original_position(fan.vertices[3])); // C: interior, must have moved
|
||||
}
|
||||
Reference in New Issue
Block a user