Add radial gradients
This commit is contained in:
@@ -38,8 +38,10 @@ uniform vec3 gradient_center;
|
||||
uniform float gradient_z_min;
|
||||
uniform float gradient_z_max;
|
||||
uniform bool gradient_linear_mode;
|
||||
uniform bool gradient_linear_radial_mode;
|
||||
uniform vec3 gradient_linear_start;
|
||||
uniform vec3 gradient_linear_end;
|
||||
uniform float gradient_linear_radius_mm;
|
||||
uniform int gradient_linear_lut_count;
|
||||
uniform vec3 gradient_linear_lut_colors[MAX_LINEAR_GRADIENT_LUT_COLORS];
|
||||
|
||||
@@ -193,9 +195,14 @@ vec3 linear_gradient_lut_color(float t)
|
||||
|
||||
vec3 linear_gradient_color(int count)
|
||||
{
|
||||
vec3 direction_vec = gradient_linear_end - gradient_linear_start;
|
||||
float denom = dot(direction_vec, direction_vec);
|
||||
float t = denom > EPSILON ? clamp(dot(world_pos.xyz - gradient_linear_start, direction_vec) / denom, 0.0, 1.0) : 0.0;
|
||||
float t = 0.0;
|
||||
if (gradient_linear_radial_mode) {
|
||||
t = clamp(length(world_pos.xyz - gradient_linear_start) / max(gradient_linear_radius_mm, EPSILON), 0.0, 1.0);
|
||||
} else {
|
||||
vec3 direction_vec = gradient_linear_end - gradient_linear_start;
|
||||
float denom = dot(direction_vec, direction_vec);
|
||||
t = denom > EPSILON ? clamp(dot(world_pos.xyz - gradient_linear_start, direction_vec) / denom, 0.0, 1.0) : 0.0;
|
||||
}
|
||||
if (count <= 0)
|
||||
return clamp(gradient_base_color, 0.0, 1.0);
|
||||
return linear_gradient_lut_color(t);
|
||||
|
||||
@@ -38,8 +38,10 @@ uniform vec3 gradient_center;
|
||||
uniform float gradient_z_min;
|
||||
uniform float gradient_z_max;
|
||||
uniform bool gradient_linear_mode;
|
||||
uniform bool gradient_linear_radial_mode;
|
||||
uniform vec3 gradient_linear_start;
|
||||
uniform vec3 gradient_linear_end;
|
||||
uniform float gradient_linear_radius_mm;
|
||||
uniform int gradient_linear_lut_count;
|
||||
uniform vec3 gradient_linear_lut_colors[MAX_LINEAR_GRADIENT_LUT_COLORS];
|
||||
|
||||
@@ -195,9 +197,14 @@ vec3 linear_gradient_lut_color(float t)
|
||||
|
||||
vec3 linear_gradient_color(int count)
|
||||
{
|
||||
vec3 direction_vec = gradient_linear_end - gradient_linear_start;
|
||||
float denom = dot(direction_vec, direction_vec);
|
||||
float t = denom > EPSILON ? clamp(dot(world_pos.xyz - gradient_linear_start, direction_vec) / denom, 0.0, 1.0) : 0.0;
|
||||
float t = 0.0;
|
||||
if (gradient_linear_radial_mode) {
|
||||
t = clamp(length(world_pos.xyz - gradient_linear_start) / max(gradient_linear_radius_mm, EPSILON), 0.0, 1.0);
|
||||
} else {
|
||||
vec3 direction_vec = gradient_linear_end - gradient_linear_start;
|
||||
float denom = dot(direction_vec, direction_vec);
|
||||
t = denom > EPSILON ? clamp(dot(world_pos.xyz - gradient_linear_start, direction_vec) / denom, 0.0, 1.0) : 0.0;
|
||||
}
|
||||
if (count <= 0)
|
||||
return clamp(gradient_base_color, 0.0, 1.0);
|
||||
return linear_gradient_lut_color(t);
|
||||
|
||||
@@ -552,6 +552,16 @@ static int surface_pattern_from_name(const std::string &name)
|
||||
return int(TextureMappingZone::ImageTexture);
|
||||
}
|
||||
|
||||
static std::string linear_gradient_mode_name(int mode)
|
||||
{
|
||||
return mode == int(TextureMappingZone::LinearGradientRadial) ? "radial" : "linear";
|
||||
}
|
||||
|
||||
static int linear_gradient_mode_from_name(const std::string &name)
|
||||
{
|
||||
return name == "radial" ? int(TextureMappingZone::LinearGradientRadial) : int(TextureMappingZone::LinearGradientLinear);
|
||||
}
|
||||
|
||||
static nlohmann::json weights_to_json(const std::string &weights, size_t expected_count)
|
||||
{
|
||||
nlohmann::json out = nlohmann::json::array();
|
||||
@@ -976,6 +986,10 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
|
||||
floats_equal(filament_transmission_distances_mm, rhs.filament_transmission_distances_mm) &&
|
||||
anchors_equal(linear_gradient_start, rhs.linear_gradient_start) &&
|
||||
anchors_equal(linear_gradient_end, rhs.linear_gradient_end) &&
|
||||
linear_gradient_mode == rhs.linear_gradient_mode &&
|
||||
std::abs(linear_gradient_radius_mm - rhs.linear_gradient_radius_mm) <= eps &&
|
||||
linear_gradient_radius_percent == rhs.linear_gradient_radius_percent &&
|
||||
std::abs(linear_gradient_radius_pct - rhs.linear_gradient_radius_pct) <= eps &&
|
||||
show_linear_gradient_direction_arrow == rhs.show_linear_gradient_direction_arrow;
|
||||
}
|
||||
|
||||
@@ -1216,6 +1230,14 @@ std::string TextureMappingManager::serialize_entries()
|
||||
nlohmann::json linear_gradient;
|
||||
linear_gradient["start"] = linear_gradient_anchor_to_json(zone.linear_gradient_start);
|
||||
linear_gradient["end"] = linear_gradient_anchor_to_json(zone.linear_gradient_end);
|
||||
linear_gradient["mode"] = linear_gradient_mode_name(zone.linear_gradient_mode);
|
||||
linear_gradient["radius_mm"] = std::isfinite(zone.linear_gradient_radius_mm) ?
|
||||
std::max(0.f, zone.linear_gradient_radius_mm) :
|
||||
TextureMappingZone::DefaultLinearGradientRadiusMm;
|
||||
linear_gradient["radius_percent"] = zone.linear_gradient_radius_percent;
|
||||
linear_gradient["radius_pct"] = std::isfinite(zone.linear_gradient_radius_pct) ?
|
||||
std::max(0.f, zone.linear_gradient_radius_pct) :
|
||||
TextureMappingZone::DefaultLinearGradientRadiusPct;
|
||||
linear_gradient["show_direction_arrow"] = zone.show_linear_gradient_direction_arrow;
|
||||
entry["linear_gradient"] = std::move(linear_gradient);
|
||||
}
|
||||
@@ -1373,6 +1395,12 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
const nlohmann::json linear_gradient = entry.value("linear_gradient", nlohmann::json::object());
|
||||
zone.linear_gradient_start = linear_gradient_anchor_from_json(linear_gradient.value("start", nlohmann::json::object()));
|
||||
zone.linear_gradient_end = linear_gradient_anchor_from_json(linear_gradient.value("end", nlohmann::json::object()));
|
||||
zone.linear_gradient_mode = linear_gradient_mode_from_name(linear_gradient.value("mode", std::string("linear")));
|
||||
const float radius_mm = linear_gradient.value("radius_mm", TextureMappingZone::DefaultLinearGradientRadiusMm);
|
||||
zone.linear_gradient_radius_mm = std::isfinite(radius_mm) ? std::max(0.f, radius_mm) : TextureMappingZone::DefaultLinearGradientRadiusMm;
|
||||
zone.linear_gradient_radius_percent = linear_gradient.value("radius_percent", TextureMappingZone::DefaultLinearGradientRadiusPercent);
|
||||
const float radius_pct = linear_gradient.value("radius_pct", TextureMappingZone::DefaultLinearGradientRadiusPct);
|
||||
zone.linear_gradient_radius_pct = std::isfinite(radius_pct) ? std::max(0.f, radius_pct) : TextureMappingZone::DefaultLinearGradientRadiusPct;
|
||||
zone.show_linear_gradient_direction_arrow = linear_gradient.value("show_direction_arrow", true);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@ struct TextureMappingZone
|
||||
LinearGradient = 2
|
||||
};
|
||||
|
||||
enum LinearGradientMode : uint8_t {
|
||||
LinearGradientLinear = 0,
|
||||
LinearGradientRadial = 1
|
||||
};
|
||||
|
||||
enum OffsetControlMode : uint8_t {
|
||||
OffsetBasic = 0,
|
||||
OffsetAdvanced = 1
|
||||
@@ -102,6 +107,10 @@ struct TextureMappingZone
|
||||
};
|
||||
|
||||
static constexpr int DefaultSurfacePattern = int(ImageTexture);
|
||||
static constexpr int DefaultLinearGradientMode = int(LinearGradientLinear);
|
||||
static constexpr float DefaultLinearGradientRadiusMm = 0.f;
|
||||
static constexpr bool DefaultLinearGradientRadiusPercent = true;
|
||||
static constexpr float DefaultLinearGradientRadiusPct = 100.f;
|
||||
static constexpr int DefaultOffsetMode = int(OffsetBasic);
|
||||
static constexpr bool DefaultOffsetRotationEnabled = true;
|
||||
static constexpr float DefaultOffsetRotations = 1.f;
|
||||
@@ -215,11 +224,16 @@ struct TextureMappingZone
|
||||
std::vector<float> filament_transmission_distances_mm;
|
||||
LinearGradientAnchor linear_gradient_start;
|
||||
LinearGradientAnchor linear_gradient_end;
|
||||
bool show_linear_gradient_direction_arrow = true;
|
||||
int linear_gradient_mode = DefaultLinearGradientMode;
|
||||
float linear_gradient_radius_mm = DefaultLinearGradientRadiusMm;
|
||||
bool linear_gradient_radius_percent = DefaultLinearGradientRadiusPercent;
|
||||
float linear_gradient_radius_pct = DefaultLinearGradientRadiusPct;
|
||||
bool show_linear_gradient_direction_arrow = true;
|
||||
|
||||
bool is_image_texture() const { return surface_pattern == int(ImageTexture); }
|
||||
bool is_2d_gradient() const { return surface_pattern == int(Gradient2D); }
|
||||
bool is_linear_gradient() const { return surface_pattern == int(LinearGradient); }
|
||||
bool is_radial_linear_gradient() const { return is_linear_gradient() && linear_gradient_mode == int(LinearGradientRadial); }
|
||||
bool is_surface_gradient() const { return is_2d_gradient() || is_linear_gradient(); }
|
||||
bool uses_perimeter_path_modulation() const { return modulation_mode == int(ModulationPerimeterPath); }
|
||||
|
||||
@@ -269,6 +283,10 @@ struct TextureMappingZone
|
||||
preview_simulate_colors = DefaultPreviewSimulateColors;
|
||||
preview_limit_resolution = DefaultPreviewLimitResolution;
|
||||
auto_adjust_filament_selection = DefaultAutoAdjustFilamentSelection;
|
||||
linear_gradient_mode = DefaultLinearGradientMode;
|
||||
linear_gradient_radius_mm = DefaultLinearGradientRadiusMm;
|
||||
linear_gradient_radius_percent = DefaultLinearGradientRadiusPercent;
|
||||
linear_gradient_radius_pct = DefaultLinearGradientRadiusPct;
|
||||
filament_strengths_pct.clear();
|
||||
filament_minimum_offsets_pct.clear();
|
||||
filament_transmission_distances_mm.clear();
|
||||
|
||||
@@ -122,6 +122,17 @@ const ModelObject *texture_mapping_anchor_model_object(const Print &print,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const PrintObject *texture_mapping_anchor_print_object(const Print &print,
|
||||
const TextureMappingZone::LinearGradientAnchor &anchor)
|
||||
{
|
||||
for (const PrintObject *print_object : print.objects()) {
|
||||
const ModelObject *model_object = print_object != nullptr ? print_object->model_object() : nullptr;
|
||||
if (texture_mapping_anchor_matches_model_object(model_object, anchor))
|
||||
return print_object;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const ModelInstance *texture_mapping_anchor_model_instance(const ModelObject *object,
|
||||
const TextureMappingZone::LinearGradientAnchor &anchor)
|
||||
{
|
||||
@@ -212,6 +223,45 @@ std::pair<Vec3f, Vec3f> texture_mapping_default_linear_gradient_points(const Pri
|
||||
return { Vec3f(cx, cy, z_min), Vec3f(cx, cy, z_max) };
|
||||
}
|
||||
|
||||
std::pair<Vec3f, float> texture_mapping_default_radial_gradient(const PrintObject &print_object)
|
||||
{
|
||||
const BoundingBox bbox = print_object.bounding_box();
|
||||
const float min_x = unscale<float>(bbox.min.x());
|
||||
const float max_x = unscale<float>(bbox.max.x());
|
||||
const float min_y = unscale<float>(bbox.min.y());
|
||||
const float max_y = unscale<float>(bbox.max.y());
|
||||
const float height = std::max(0.01f, unscale<float>(print_object.height()));
|
||||
const Vec3f center(0.5f * (min_x + max_x), 0.5f * (min_y + max_y), 0.5f * height);
|
||||
const Vec3f diagonal(std::max(0.f, max_x - min_x), std::max(0.f, max_y - min_y), height);
|
||||
const float radius = std::max(0.01f, 0.5f * diagonal.norm());
|
||||
return { center, radius };
|
||||
}
|
||||
|
||||
float texture_mapping_linear_gradient_radius_mm(const PrintObject &print_object,
|
||||
const TextureMappingZone &zone,
|
||||
float default_radius_mm)
|
||||
{
|
||||
if (!zone.linear_gradient_radius_percent) {
|
||||
const float radius_mm = std::isfinite(zone.linear_gradient_radius_mm) ? zone.linear_gradient_radius_mm : default_radius_mm;
|
||||
return std::max(0.01f, radius_mm);
|
||||
}
|
||||
|
||||
const float radius_value = std::isfinite(zone.linear_gradient_radius_pct) ?
|
||||
std::max(0.f, zone.linear_gradient_radius_pct) :
|
||||
TextureMappingZone::DefaultLinearGradientRadiusPct;
|
||||
if (zone.linear_gradient_start.valid) {
|
||||
const Print *print = print_object.print();
|
||||
const PrintObject *anchor_print_object = print != nullptr ?
|
||||
texture_mapping_anchor_print_object(*print, zone.linear_gradient_start) :
|
||||
nullptr;
|
||||
if (anchor_print_object != nullptr)
|
||||
return std::max(0.01f, texture_mapping_default_radial_gradient(*anchor_print_object).second * radius_value / 100.f);
|
||||
return std::max(0.01f, radius_value);
|
||||
}
|
||||
|
||||
return std::max(0.01f, default_radius_mm * radius_value / 100.f);
|
||||
}
|
||||
|
||||
int texture_mapping_color_hex_digit(char ch)
|
||||
{
|
||||
return ch >= '0' && ch <= '9' ? ch - '0' :
|
||||
@@ -2967,20 +3017,30 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
context.nonlinear_offset_adjustment = zone.nonlinear_offset_adjustment;
|
||||
context.object_center = print_object.bounding_box().center();
|
||||
if (linear_gradient_mode) {
|
||||
const bool radial_mode = zone.linear_gradient_mode == int(TextureMappingZone::LinearGradientRadial);
|
||||
auto default_points = texture_mapping_default_linear_gradient_points(print_object);
|
||||
auto default_radial = texture_mapping_default_radial_gradient(print_object);
|
||||
std::optional<Vec3f> start =
|
||||
texture_mapping_linear_gradient_anchor_print_point(print_object,
|
||||
zone.linear_gradient_start,
|
||||
plate_origin_mm_override);
|
||||
std::optional<Vec3f> end =
|
||||
texture_mapping_linear_gradient_anchor_print_point(print_object,
|
||||
zone.linear_gradient_end,
|
||||
plate_origin_mm_override);
|
||||
context.linear_gradient_start_mm = start ? *start : default_points.first;
|
||||
context.linear_gradient_end_mm = end ? *end : default_points.second;
|
||||
if ((context.linear_gradient_end_mm - context.linear_gradient_start_mm).squaredNorm() <= 1e-8f) {
|
||||
context.linear_gradient_start_mm = default_points.first;
|
||||
context.linear_gradient_end_mm = default_points.second;
|
||||
std::optional<Vec3f> end;
|
||||
if (!radial_mode)
|
||||
end = texture_mapping_linear_gradient_anchor_print_point(print_object,
|
||||
zone.linear_gradient_end,
|
||||
plate_origin_mm_override);
|
||||
context.linear_gradient_radial_mode = radial_mode;
|
||||
if (radial_mode) {
|
||||
context.linear_gradient_start_mm = start ? *start : default_radial.first;
|
||||
context.linear_gradient_radius_mm = texture_mapping_linear_gradient_radius_mm(print_object, zone, default_radial.second);
|
||||
context.linear_gradient_end_mm = context.linear_gradient_start_mm + Vec3f::UnitX() * context.linear_gradient_radius_mm;
|
||||
} else {
|
||||
context.linear_gradient_start_mm = start ? *start : default_points.first;
|
||||
context.linear_gradient_end_mm = end ? *end : default_points.second;
|
||||
if ((context.linear_gradient_end_mm - context.linear_gradient_start_mm).squaredNorm() <= 1e-8f) {
|
||||
context.linear_gradient_start_mm = default_points.first;
|
||||
context.linear_gradient_end_mm = default_points.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
context.active_component_id = active_component_id;
|
||||
@@ -3052,18 +3112,23 @@ float texture_mapping_offset_surface_inset_mm(const TextureMappingOffsetContext
|
||||
}
|
||||
inset_strength = std::clamp(1.f - desired_strength, 0.f, 1.f);
|
||||
} else if (context.linear_gradient_mode) {
|
||||
const Vec3f gradient_vec = context.linear_gradient_end_mm - context.linear_gradient_start_mm;
|
||||
const float denom = gradient_vec.squaredNorm();
|
||||
if (denom <= 1e-8f) {
|
||||
inset_strength = 0.f;
|
||||
float t = 0.f;
|
||||
float z_mm = context.layer != nullptr ? float(context.layer->print_z) : 0.f;
|
||||
if (std::isfinite(surface_v_mm))
|
||||
z_mm = surface_v_mm;
|
||||
if (!std::isfinite(z_mm))
|
||||
z_mm = 0.f;
|
||||
const Vec3f sample(unscale<float>(point.x()), unscale<float>(point.y()), z_mm);
|
||||
if (context.linear_gradient_radial_mode) {
|
||||
const float radius = std::max(0.01f, context.linear_gradient_radius_mm);
|
||||
t = clamp01f((sample - context.linear_gradient_start_mm).norm() / radius);
|
||||
} else {
|
||||
float z_mm = context.layer != nullptr ? float(context.layer->print_z) : 0.f;
|
||||
if (std::isfinite(surface_v_mm))
|
||||
z_mm = surface_v_mm;
|
||||
if (!std::isfinite(z_mm))
|
||||
z_mm = 0.f;
|
||||
const Vec3f sample(unscale<float>(point.x()), unscale<float>(point.y()), z_mm);
|
||||
const float t = clamp01f((sample - context.linear_gradient_start_mm).dot(gradient_vec) / denom);
|
||||
const Vec3f gradient_vec = context.linear_gradient_end_mm - context.linear_gradient_start_mm;
|
||||
const float denom = gradient_vec.squaredNorm();
|
||||
if (denom > 1e-8f)
|
||||
t = clamp01f((sample - context.linear_gradient_start_mm).dot(gradient_vec) / denom);
|
||||
}
|
||||
if (context.linear_gradient_radial_mode || (context.linear_gradient_end_mm - context.linear_gradient_start_mm).squaredNorm() > 1e-8f) {
|
||||
float desired_strength = context.active_component_idx == 0 ? 1.f - t :
|
||||
context.active_component_idx == 1 ? t :
|
||||
0.f;
|
||||
@@ -3071,6 +3136,8 @@ float texture_mapping_offset_surface_inset_mm(const TextureMappingOffsetContext
|
||||
if (max_strength > EPSILON)
|
||||
desired_strength = clamp01f(desired_strength / max_strength);
|
||||
inset_strength = std::clamp(1.f - desired_strength, 0.f, 1.f);
|
||||
} else {
|
||||
inset_strength = 0.f;
|
||||
}
|
||||
} else {
|
||||
double theta_direction_x = outward_x;
|
||||
|
||||
@@ -64,6 +64,8 @@ struct TextureMappingOffsetContext {
|
||||
Point object_center;
|
||||
Vec3f linear_gradient_start_mm { Vec3f::Zero() };
|
||||
Vec3f linear_gradient_end_mm { Vec3f::Zero() };
|
||||
bool linear_gradient_radial_mode { false };
|
||||
float linear_gradient_radius_mm { 0.f };
|
||||
unsigned int active_component_id { 0 };
|
||||
size_t active_component_idx { size_t(-1) };
|
||||
std::vector<unsigned int> component_ids;
|
||||
|
||||
@@ -194,6 +194,19 @@ const ModelObject *linear_gradient_anchor_model_object(const Model &model,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool linear_gradient_anchor_matches_model_object(const Model &model,
|
||||
const ModelObject *object,
|
||||
const TextureMappingZone::LinearGradientAnchor &anchor)
|
||||
{
|
||||
if (object == nullptr)
|
||||
return false;
|
||||
if (anchor.object_backup_id >= 0 && linear_gradient_model_object_backup_id(object) == anchor.object_backup_id)
|
||||
return true;
|
||||
if (anchor.object_id != 0 && object->id().id == anchor.object_id)
|
||||
return true;
|
||||
return anchor.object_index_valid && anchor.object_index < model.objects.size() && model.objects[anchor.object_index] == object;
|
||||
}
|
||||
|
||||
const ModelInstance *linear_gradient_anchor_model_instance(const ModelObject *object,
|
||||
const TextureMappingZone::LinearGradientAnchor &anchor)
|
||||
{
|
||||
@@ -233,6 +246,105 @@ std::optional<Vec3f> linear_gradient_anchor_global_point(const TextureMappingZon
|
||||
return linear_gradient_vec3_is_finite(fallback) ? std::optional<Vec3f>(fallback) : std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<Vec3f> linear_gradient_anchor_global_point(const GLVolumePtrs &volumes,
|
||||
const TextureMappingZone::LinearGradientAnchor &anchor)
|
||||
{
|
||||
if (!anchor.valid)
|
||||
return std::nullopt;
|
||||
|
||||
const Vec3f local = linear_gradient_anchor_array_point(anchor.local_point);
|
||||
const Model &model = GUI::wxGetApp().model();
|
||||
const ModelObject *anchor_object = linear_gradient_anchor_model_object(model, anchor);
|
||||
const ModelInstance *anchor_instance = linear_gradient_anchor_model_instance(anchor_object, anchor);
|
||||
for (const GLVolume *volume : volumes) {
|
||||
if (volume == nullptr ||
|
||||
volume->object_idx() < 0 ||
|
||||
volume->instance_idx() < 0 ||
|
||||
volume->object_idx() >= int(model.objects.size()))
|
||||
continue;
|
||||
|
||||
const ModelObject *object = model.objects[size_t(volume->object_idx())];
|
||||
if (object == nullptr || !linear_gradient_anchor_matches_model_object(model, object, anchor))
|
||||
continue;
|
||||
if (size_t(volume->instance_idx()) >= object->instances.size())
|
||||
continue;
|
||||
|
||||
const ModelInstance *instance = object->instances[size_t(volume->instance_idx())];
|
||||
if (anchor_instance != nullptr && instance != anchor_instance)
|
||||
continue;
|
||||
if (anchor_instance == nullptr && object->instances.size() != 1)
|
||||
continue;
|
||||
|
||||
const Vec3f global = (volume->get_instance_transformation().get_matrix() * local.cast<double>()).cast<float>();
|
||||
if (linear_gradient_vec3_is_finite(global))
|
||||
return global;
|
||||
}
|
||||
|
||||
return linear_gradient_anchor_global_point(anchor);
|
||||
}
|
||||
|
||||
std::optional<float> linear_gradient_anchor_object_radius(const GLVolumePtrs &volumes,
|
||||
const TextureMappingZone::LinearGradientAnchor &anchor)
|
||||
{
|
||||
if (!anchor.valid)
|
||||
return std::nullopt;
|
||||
|
||||
const Model &model = GUI::wxGetApp().model();
|
||||
const ModelObject *anchor_object = linear_gradient_anchor_model_object(model, anchor);
|
||||
const ModelInstance *anchor_instance = linear_gradient_anchor_model_instance(anchor_object, anchor);
|
||||
BoundingBoxf3 bbox;
|
||||
bool defined = false;
|
||||
for (const GLVolume *volume : volumes) {
|
||||
if (volume == nullptr ||
|
||||
volume->object_idx() < 0 ||
|
||||
volume->instance_idx() < 0 ||
|
||||
volume->object_idx() >= int(model.objects.size()))
|
||||
continue;
|
||||
|
||||
const ModelObject *object = model.objects[size_t(volume->object_idx())];
|
||||
if (object == nullptr || !linear_gradient_anchor_matches_model_object(model, object, anchor))
|
||||
continue;
|
||||
if (size_t(volume->instance_idx()) >= object->instances.size())
|
||||
continue;
|
||||
|
||||
const ModelInstance *instance = object->instances[size_t(volume->instance_idx())];
|
||||
if (anchor_instance != nullptr && instance != anchor_instance)
|
||||
continue;
|
||||
if (anchor_instance == nullptr && object->instances.size() != 1)
|
||||
continue;
|
||||
|
||||
bbox.merge(volume->transformed_convex_hull_bounding_box());
|
||||
defined = true;
|
||||
}
|
||||
|
||||
if (!defined)
|
||||
return std::nullopt;
|
||||
const float radius = 0.5f * (bbox.max.cast<float>() - bbox.min.cast<float>()).norm();
|
||||
return std::isfinite(radius) && radius > 0.f ? std::optional<float>(radius) : std::nullopt;
|
||||
}
|
||||
|
||||
float linear_gradient_radial_radius_mm(const GLVolumePtrs &volumes,
|
||||
const TextureMappingZone &zone,
|
||||
float default_radius_mm)
|
||||
{
|
||||
if (!zone.linear_gradient_radius_percent) {
|
||||
const float radius_mm = std::isfinite(zone.linear_gradient_radius_mm) ? zone.linear_gradient_radius_mm : default_radius_mm;
|
||||
return std::max(0.01f, radius_mm);
|
||||
}
|
||||
|
||||
const float radius_value = std::isfinite(zone.linear_gradient_radius_pct) ?
|
||||
std::max(0.f, zone.linear_gradient_radius_pct) :
|
||||
TextureMappingZone::DefaultLinearGradientRadiusPct;
|
||||
if (zone.linear_gradient_start.valid) {
|
||||
const std::optional<float> anchor_radius = linear_gradient_anchor_object_radius(volumes, zone.linear_gradient_start);
|
||||
if (anchor_radius)
|
||||
return std::max(0.01f, *anchor_radius * radius_value / 100.f);
|
||||
return std::max(0.01f, radius_value);
|
||||
}
|
||||
|
||||
return std::max(0.01f, default_radius_mm * radius_value / 100.f);
|
||||
}
|
||||
|
||||
bool model_volume_uses_texture_mapping_zone(const ModelVolume &model_volume, unsigned int zone_id)
|
||||
{
|
||||
if (zone_id == 0)
|
||||
@@ -283,6 +395,8 @@ struct LinearGradientArrowUsage {
|
||||
bool any { false };
|
||||
Vec3f default_start { Vec3f::Zero() };
|
||||
Vec3f default_end { Vec3f::UnitZ() };
|
||||
Vec3f radial_center { Vec3f::Zero() };
|
||||
float radial_radius { 1.f };
|
||||
};
|
||||
|
||||
LinearGradientArrowUsage linear_gradient_arrow_usage(const GLVolumePtrs &volumes, unsigned int zone_id)
|
||||
@@ -326,12 +440,15 @@ LinearGradientArrowUsage linear_gradient_arrow_usage(const GLVolumePtrs &volumes
|
||||
|
||||
Vec3f center_sum = Vec3f::Zero();
|
||||
float max_z = 0.f;
|
||||
float max_radius = 0.01f;
|
||||
size_t count = 0;
|
||||
for (const auto &item : object_boxes) {
|
||||
if (!item.second.defined)
|
||||
continue;
|
||||
center_sum += item.second.center().cast<float>();
|
||||
const Vec3f center = item.second.center().cast<float>();
|
||||
center_sum += center;
|
||||
max_z = std::max(max_z, float(item.second.max.z()));
|
||||
max_radius = std::max(max_radius, 0.5f * (item.second.max.cast<float>() - item.second.min.cast<float>()).norm());
|
||||
++count;
|
||||
}
|
||||
if (count == 0)
|
||||
@@ -341,6 +458,8 @@ LinearGradientArrowUsage linear_gradient_arrow_usage(const GLVolumePtrs &volumes
|
||||
usage.any = true;
|
||||
usage.default_start = Vec3f(avg.x(), avg.y(), 0.f);
|
||||
usage.default_end = Vec3f(avg.x(), avg.y(), std::max(0.01f, max_z));
|
||||
usage.radial_center = avg;
|
||||
usage.radial_radius = std::max(0.01f, max_radius);
|
||||
return usage;
|
||||
}
|
||||
|
||||
@@ -479,6 +598,63 @@ void append_linear_gradient_sphere(GUI::GLModel::Geometry &geometry,
|
||||
}
|
||||
}
|
||||
|
||||
void append_linear_gradient_dashed_ring(GUI::GLModel::Geometry &geometry,
|
||||
const Vec3f ¢er,
|
||||
const Vec3f &u,
|
||||
const Vec3f &v,
|
||||
float radius,
|
||||
float tube_radius,
|
||||
const ColorRGBA &color)
|
||||
{
|
||||
constexpr int dash_count = 20;
|
||||
constexpr int arc_steps = 4;
|
||||
constexpr int tube_sectors = 8;
|
||||
constexpr float dash_fraction = 0.42f;
|
||||
if (radius <= 1e-5f || tube_radius <= 1e-6f)
|
||||
return;
|
||||
Vec3f normal = u.cross(v).normalized();
|
||||
if (!linear_gradient_vec3_is_finite(normal) || normal.squaredNorm() <= 1e-8f)
|
||||
normal = Vec3f::UnitZ();
|
||||
for (int dash = 0; dash < dash_count; ++dash) {
|
||||
const float a_start = 2.f * float(PI) * float(dash) / float(dash_count);
|
||||
const float a_end = a_start + 2.f * float(PI) * dash_fraction / float(dash_count);
|
||||
std::vector<std::vector<unsigned int>> ids(size_t(arc_steps + 1), std::vector<unsigned int>(size_t(tube_sectors + 1), 0));
|
||||
for (int step = 0; step <= arc_steps; ++step) {
|
||||
const float t = float(step) / float(arc_steps);
|
||||
const float a = a_start + (a_end - a_start) * t;
|
||||
const Vec3f radial = std::cos(a) * u + std::sin(a) * v;
|
||||
const Vec3f p = center + radius * radial;
|
||||
for (int sector = 0; sector <= tube_sectors; ++sector) {
|
||||
const float b = 2.f * float(PI) * float(sector) / float(tube_sectors);
|
||||
const Vec3f tube_normal = std::cos(b) * radial + std::sin(b) * normal;
|
||||
ids[size_t(step)][size_t(sector)] =
|
||||
linear_gradient_add_vertex(geometry, p + tube_radius * tube_normal, tube_normal, color);
|
||||
}
|
||||
}
|
||||
for (int step = 0; step < arc_steps; ++step) {
|
||||
for (int sector = 0; sector < tube_sectors; ++sector) {
|
||||
const unsigned int a = ids[size_t(step)][size_t(sector)];
|
||||
const unsigned int b = ids[size_t(step + 1)][size_t(sector)];
|
||||
const unsigned int c = ids[size_t(step)][size_t(sector + 1)];
|
||||
const unsigned int d = ids[size_t(step + 1)][size_t(sector + 1)];
|
||||
geometry.add_triangle(a, b, c);
|
||||
geometry.add_triangle(c, b, d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void append_linear_gradient_dashed_sphere(GUI::GLModel::Geometry &geometry,
|
||||
const Vec3f ¢er,
|
||||
float radius,
|
||||
float tube_radius,
|
||||
const ColorRGBA &color)
|
||||
{
|
||||
append_linear_gradient_dashed_ring(geometry, center, Vec3f::UnitX(), Vec3f::UnitY(), radius, tube_radius, color);
|
||||
append_linear_gradient_dashed_ring(geometry, center, Vec3f::UnitX(), Vec3f::UnitZ(), radius, tube_radius, color);
|
||||
append_linear_gradient_dashed_ring(geometry, center, Vec3f::UnitY(), Vec3f::UnitZ(), radius, tube_radius, color);
|
||||
}
|
||||
|
||||
void append_linear_gradient_arrow(GUI::GLModel::Geometry &geometry,
|
||||
const Vec3f &start,
|
||||
const Vec3f &end,
|
||||
@@ -1235,7 +1411,9 @@ void GLVolume::render_mmu_texture_preview(const Transform3d &view_matrix,
|
||||
int print_volume_type,
|
||||
const std::array<float, 4> &print_volume_xy,
|
||||
const std::array<float, 2> &print_volume_z,
|
||||
bool opaque)
|
||||
bool opaque,
|
||||
const SurfaceGradientAnchorResolver *surface_gradient_anchor_resolver,
|
||||
const SurfaceGradientAnchorRadiusResolver *surface_gradient_anchor_radius_resolver)
|
||||
{
|
||||
if (picking || !printable || object_idx() < 0 || volume_idx() < 0)
|
||||
return;
|
||||
@@ -1367,7 +1545,9 @@ void GLVolume::render_mmu_texture_preview(const Transform3d &view_matrix,
|
||||
print_volume_xy,
|
||||
print_volume_z,
|
||||
opaque,
|
||||
model_volume);
|
||||
model_volume,
|
||||
surface_gradient_anchor_resolver,
|
||||
surface_gradient_anchor_radius_resolver);
|
||||
}
|
||||
|
||||
if (this->is_left_handed())
|
||||
@@ -2905,6 +3085,12 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
|
||||
float(m_clipping_plane[2]),
|
||||
float(m_clipping_plane[3])
|
||||
};
|
||||
const SurfaceGradientAnchorResolver surface_gradient_anchor_resolver = [this](const TextureMappingZone::LinearGradientAnchor &anchor) {
|
||||
return linear_gradient_anchor_global_point(this->volumes, anchor);
|
||||
};
|
||||
const SurfaceGradientAnchorRadiusResolver surface_gradient_anchor_radius_resolver = [this](const TextureMappingZone::LinearGradientAnchor &anchor) {
|
||||
return linear_gradient_anchor_object_radius(this->volumes, anchor);
|
||||
};
|
||||
const bool render_model_texture_preview =
|
||||
volume.first->object_idx() >= 0 && volume.first->volume_idx() >= 0 && !volume.first->is_wipe_tower &&
|
||||
!volume.first->is_modifier && !volume.first->is_extrusion_path;
|
||||
@@ -2916,7 +3102,10 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type,
|
||||
texture_preview_clipping_plane,
|
||||
texture_preview_print_volume_type,
|
||||
m_print_volume.data,
|
||||
m_print_volume.zs);
|
||||
m_print_volume.zs,
|
||||
false,
|
||||
&surface_gradient_anchor_resolver,
|
||||
&surface_gradient_anchor_radius_resolver);
|
||||
if (volume.first->is_wipe_tower) {
|
||||
GLWipeTowerVolume *wipe_tower_volume = static_cast<GLWipeTowerVolume *>(volume.first);
|
||||
wipe_tower_volume->render_prime_tower_image_preview(view_matrix,
|
||||
@@ -2976,6 +3165,8 @@ void GLVolumeCollection::render_linear_gradient_direction_arrows(const Transform
|
||||
black_geometry.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3N3C4 };
|
||||
GUI::GLModel::Geometry color_geometry;
|
||||
color_geometry.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3N3C4 };
|
||||
GUI::GLModel::Geometry radius_geometry;
|
||||
radius_geometry.format = { GUI::GLModel::Geometry::EPrimitiveType::Triangles, GUI::GLModel::Geometry::EVertexLayout::P3N3C4 };
|
||||
|
||||
for (const TextureMappingZone &zone : texture_mgr.zones()) {
|
||||
if (!zone.enabled || zone.deleted || !zone.is_linear_gradient() || !zone.show_linear_gradient_direction_arrow)
|
||||
@@ -2986,24 +3177,34 @@ void GLVolumeCollection::render_linear_gradient_direction_arrows(const Transform
|
||||
continue;
|
||||
|
||||
const LinearGradientArrowUsage usage = linear_gradient_arrow_usage(volumes, zone.zone_id);
|
||||
const std::optional<Vec3f> start_anchor = linear_gradient_anchor_global_point(zone.linear_gradient_start);
|
||||
const std::optional<Vec3f> end_anchor = linear_gradient_anchor_global_point(zone.linear_gradient_end);
|
||||
const std::optional<Vec3f> start_anchor = linear_gradient_anchor_global_point(volumes, zone.linear_gradient_start);
|
||||
const bool radial_mode = zone.linear_gradient_mode == int(TextureMappingZone::LinearGradientRadial);
|
||||
const std::optional<Vec3f> end_anchor = radial_mode ?
|
||||
std::nullopt :
|
||||
linear_gradient_anchor_global_point(volumes, zone.linear_gradient_end);
|
||||
if (!usage.any && !start_anchor && !end_anchor)
|
||||
continue;
|
||||
|
||||
Vec3f start = start_anchor ? *start_anchor : usage.default_start;
|
||||
Vec3f end = end_anchor ? *end_anchor : usage.default_end;
|
||||
Vec3f start = start_anchor ? *start_anchor : (radial_mode ? usage.radial_center : usage.default_start);
|
||||
Vec3f end = usage.default_end;
|
||||
if (radial_mode)
|
||||
end = start + Vec3f::UnitX();
|
||||
if (end_anchor)
|
||||
end = *end_anchor;
|
||||
if (!start_anchor && !usage.any)
|
||||
start = end - Vec3f::UnitZ();
|
||||
start = radial_mode ? end - Vec3f::UnitX() : end - Vec3f::UnitZ();
|
||||
if (!end_anchor && !usage.any)
|
||||
end = start + Vec3f::UnitZ();
|
||||
end = start + (radial_mode ? Vec3f::UnitX() : Vec3f::UnitZ());
|
||||
if (!linear_gradient_vec3_is_finite(start) || !linear_gradient_vec3_is_finite(end))
|
||||
continue;
|
||||
|
||||
Vec3f delta = end - start;
|
||||
float length = delta.norm();
|
||||
if (length <= 1e-5f) {
|
||||
if (usage.any) {
|
||||
if (radial_mode) {
|
||||
delta = Vec3f::UnitX();
|
||||
length = 1.f;
|
||||
} else if (usage.any) {
|
||||
start = usage.default_start;
|
||||
end = usage.default_end;
|
||||
delta = end - start;
|
||||
@@ -3012,6 +3213,11 @@ void GLVolumeCollection::render_linear_gradient_direction_arrows(const Transform
|
||||
if (length <= 1e-5f)
|
||||
continue;
|
||||
}
|
||||
if (radial_mode) {
|
||||
length = linear_gradient_radial_radius_mm(volumes, zone, usage.radial_radius);
|
||||
end = start + Vec3f::UnitX() * length;
|
||||
delta = end - start;
|
||||
}
|
||||
|
||||
const std::array<float, 3> start_color = linear_gradient_filament_color(component_ids[0], filament_colors);
|
||||
const std::array<float, 3> end_color = linear_gradient_filament_color(component_ids[1], filament_colors);
|
||||
@@ -3040,11 +3246,15 @@ void GLVolumeCollection::render_linear_gradient_direction_arrows(const Transform
|
||||
const float sphere_radius = shaft_radius * 2.45f;
|
||||
if (start_anchor)
|
||||
append_linear_gradient_sphere(black_geometry, *start_anchor, sphere_radius, ColorRGBA::BLACK());
|
||||
if (end_anchor)
|
||||
if (!radial_mode && end_anchor)
|
||||
append_linear_gradient_sphere(black_geometry, *end_anchor, sphere_radius, ColorRGBA::BLACK());
|
||||
if (radial_mode) {
|
||||
const float tube_radius = 0.5f;
|
||||
append_linear_gradient_dashed_sphere(radius_geometry, start, length, tube_radius, ColorRGBA(0.f, 0.f, 0.f, 0.4f));
|
||||
}
|
||||
}
|
||||
|
||||
if (black_geometry.is_empty() && color_geometry.is_empty())
|
||||
if (black_geometry.is_empty() && color_geometry.is_empty() && radius_geometry.is_empty())
|
||||
return;
|
||||
|
||||
GLShaderProgram *shader = GUI::wxGetApp().get_shader("flat_vertex_color");
|
||||
@@ -3079,6 +3289,18 @@ void GLVolumeCollection::render_linear_gradient_direction_arrows(const Transform
|
||||
shader->set_uniform("view_model_matrix", view_matrix);
|
||||
shader->set_uniform("projection_matrix", projection_matrix);
|
||||
|
||||
if (!radius_geometry.is_empty()) {
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDepthFunc(GL_LEQUAL));
|
||||
glsafe(::glDepthMask(GL_FALSE));
|
||||
GUI::GLModel radius_model;
|
||||
radius_model.init_from(std::move(radius_geometry));
|
||||
radius_model.render(shader);
|
||||
}
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
glsafe(::glDepthMask(GL_FALSE));
|
||||
|
||||
if (!black_geometry.is_empty()) {
|
||||
GUI::GLModel black_model;
|
||||
black_model.init_from(std::move(black_geometry));
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "GLModel.hpp"
|
||||
#include "GLTexture.hpp"
|
||||
#include "GLShader.hpp"
|
||||
#include "MMUPaintedTexturePreview.hpp"
|
||||
#include "MeshUtils.hpp"
|
||||
|
||||
#include <functional>
|
||||
@@ -370,7 +371,9 @@ public:
|
||||
int print_volume_type = -1,
|
||||
const std::array<float, 4> &print_volume_xy = std::array<float, 4>{ 0.f, 0.f, 0.f, 0.f },
|
||||
const std::array<float, 2> &print_volume_z = std::array<float, 2>{ 0.f, 0.f },
|
||||
bool opaque = false);
|
||||
bool opaque = false,
|
||||
const SurfaceGradientAnchorResolver *surface_gradient_anchor_resolver = nullptr,
|
||||
const SurfaceGradientAnchorRadiusResolver *surface_gradient_anchor_radius_resolver = nullptr);
|
||||
void invalidate_texture_mapping_preview();
|
||||
|
||||
void set_bounding_boxes_as_dirty() {
|
||||
|
||||
@@ -2042,7 +2042,6 @@ void GLCanvas3D::render(bool only_init)
|
||||
_render_platelist(camera.get_view_matrix(), camera.get_projection_matrix(), !camera.is_looking_downward(), only_current, true, hover_id);
|
||||
// BBS: GUI refactor: add canvas size as parameters
|
||||
_render_gcode(cnv_size.get_width(), cnv_size.get_height());
|
||||
m_volumes.render_linear_gradient_direction_arrows(camera.get_view_matrix(), camera.get_projection_matrix());
|
||||
}
|
||||
/* assemble render*/
|
||||
else if (m_canvas_type == ECanvasType::CanvasAssembleView) {
|
||||
|
||||
@@ -271,9 +271,13 @@ void GLGizmoTextureGradientPointPicker::on_render_input_window(float, float, flo
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.08f, 0.09f, 0.10f, 0.88f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f));
|
||||
if (ImGui::Begin("linear_gradient_point_picker_overlay", nullptr, flags)) {
|
||||
const std::string message = m_target == Target::End ?
|
||||
_u8L("Click an object to set gradient end point") :
|
||||
_u8L("Click an object to set gradient start point");
|
||||
const std::string message = m_radial_mode ?
|
||||
(m_target == Target::End ?
|
||||
_u8L("Click an object to set radial gradient radius point") :
|
||||
_u8L("Click an object to set radial gradient center point")) :
|
||||
(m_target == Target::End ?
|
||||
_u8L("Click an object to set gradient end point") :
|
||||
_u8L("Click an object to set gradient start point"));
|
||||
ImGui::TextUnformatted(message.c_str());
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
HoverCallback hover_callback = HoverCallback(),
|
||||
CancelCallback cancel_callback = CancelCallback());
|
||||
void cancel_hover_preview();
|
||||
void set_radial_mode(bool radial_mode) { m_radial_mode = radial_mode; }
|
||||
Target target() const { return m_target; }
|
||||
|
||||
private:
|
||||
@@ -65,6 +66,7 @@ private:
|
||||
bool m_has_hover { false };
|
||||
bool m_hover_preview_emitted { false };
|
||||
bool m_last_hover_preview_had_hit { false };
|
||||
bool m_radial_mode { false };
|
||||
Vec2d m_mouse_pos { Vec2d::Zero() };
|
||||
};
|
||||
|
||||
|
||||
@@ -120,8 +120,10 @@ struct SurfaceGradientPreviewSettings
|
||||
float z_min = 0.f;
|
||||
float z_max = 0.f;
|
||||
bool linear_gradient = false;
|
||||
bool linear_gradient_radial = false;
|
||||
Vec3f linear_start = Vec3f::Zero();
|
||||
Vec3f linear_end = Vec3f::UnitZ();
|
||||
float linear_radius_mm = 1.f;
|
||||
std::vector<std::array<float, 3>> linear_gradient_lut_colors;
|
||||
};
|
||||
|
||||
@@ -4233,7 +4235,8 @@ std::optional<Vec3f> surface_gradient_anchor_global_point(const TextureMappingZo
|
||||
|
||||
std::optional<Vec3f> surface_gradient_anchor_world_point_for_volume(const ModelVolume &model_volume,
|
||||
const Transform3d &world_matrix,
|
||||
const TextureMappingZone::LinearGradientAnchor &anchor)
|
||||
const TextureMappingZone::LinearGradientAnchor &anchor,
|
||||
const SurfaceGradientAnchorResolver *surface_gradient_anchor_resolver)
|
||||
{
|
||||
if (!anchor.valid)
|
||||
return std::nullopt;
|
||||
@@ -4248,13 +4251,105 @@ std::optional<Vec3f> surface_gradient_anchor_world_point_for_volume(const ModelV
|
||||
return world;
|
||||
}
|
||||
|
||||
if (surface_gradient_anchor_resolver != nullptr) {
|
||||
const std::optional<Vec3f> live_global = (*surface_gradient_anchor_resolver)(anchor);
|
||||
if (live_global && surface_gradient_anchor_vec_finite(*live_global))
|
||||
return live_global;
|
||||
}
|
||||
|
||||
return surface_gradient_anchor_global_point(anchor);
|
||||
}
|
||||
|
||||
std::optional<float> surface_gradient_anchor_object_radius(const TextureMappingZone::LinearGradientAnchor &anchor)
|
||||
{
|
||||
if (!anchor.valid)
|
||||
return std::nullopt;
|
||||
|
||||
const Model &model = GUI::wxGetApp().model();
|
||||
const ModelObject *object = surface_gradient_anchor_model_object(model, anchor);
|
||||
if (object == nullptr)
|
||||
return std::nullopt;
|
||||
|
||||
const ModelInstance *anchor_instance = surface_gradient_anchor_model_instance(object, anchor);
|
||||
BoundingBoxf3 bbox;
|
||||
bool defined = false;
|
||||
auto merge_instance = [&bbox, &defined, object](const ModelInstance *instance) {
|
||||
if (instance == nullptr)
|
||||
return;
|
||||
for (const ModelVolume *volume : object->volumes) {
|
||||
if (volume == nullptr)
|
||||
continue;
|
||||
bbox.merge(volume->mesh().transformed_bounding_box(instance->get_matrix() * volume->get_matrix(), 0.0));
|
||||
defined = true;
|
||||
}
|
||||
};
|
||||
if (anchor_instance != nullptr)
|
||||
merge_instance(anchor_instance);
|
||||
else
|
||||
for (const ModelInstance *instance : object->instances)
|
||||
merge_instance(instance);
|
||||
|
||||
if (!defined)
|
||||
return std::nullopt;
|
||||
const float radius = 0.5f * (bbox.max.cast<float>() - bbox.min.cast<float>()).norm();
|
||||
return std::isfinite(radius) && radius > 0.f ? std::optional<float>(radius) : std::nullopt;
|
||||
}
|
||||
|
||||
float surface_gradient_linear_radius_mm(const TextureMappingZone &zone,
|
||||
float default_radius_mm,
|
||||
const SurfaceGradientAnchorRadiusResolver *surface_gradient_anchor_radius_resolver)
|
||||
{
|
||||
if (!zone.linear_gradient_radius_percent) {
|
||||
const float radius_mm = std::isfinite(zone.linear_gradient_radius_mm) ? zone.linear_gradient_radius_mm : default_radius_mm;
|
||||
return std::max(0.01f, radius_mm);
|
||||
}
|
||||
|
||||
const float radius_value = std::isfinite(zone.linear_gradient_radius_pct) ?
|
||||
std::max(0.f, zone.linear_gradient_radius_pct) :
|
||||
TextureMappingZone::DefaultLinearGradientRadiusPct;
|
||||
if (zone.linear_gradient_start.valid) {
|
||||
std::optional<float> anchor_radius;
|
||||
if (surface_gradient_anchor_radius_resolver != nullptr)
|
||||
anchor_radius = (*surface_gradient_anchor_radius_resolver)(zone.linear_gradient_start);
|
||||
if (!anchor_radius)
|
||||
anchor_radius = surface_gradient_anchor_object_radius(zone.linear_gradient_start);
|
||||
if (anchor_radius)
|
||||
return std::max(0.01f, *anchor_radius * radius_value / 100.f);
|
||||
return std::max(0.01f, radius_value);
|
||||
}
|
||||
|
||||
return std::max(0.01f, default_radius_mm * radius_value / 100.f);
|
||||
}
|
||||
|
||||
float surface_gradient_object_radius_for_volume(const ModelVolume &model_volume,
|
||||
const Transform3d &world_matrix,
|
||||
float fallback_radius)
|
||||
{
|
||||
const ModelObject *object = model_volume.get_object();
|
||||
if (object == nullptr)
|
||||
return fallback_radius;
|
||||
|
||||
const Transform3d instance_matrix = world_matrix * model_volume.get_matrix().inverse();
|
||||
BoundingBoxf3 bbox;
|
||||
bool defined = false;
|
||||
for (const ModelVolume *volume : object->volumes) {
|
||||
if (volume == nullptr)
|
||||
continue;
|
||||
bbox.merge(volume->mesh().transformed_bounding_box(instance_matrix * volume->get_matrix(), 0.0));
|
||||
defined = true;
|
||||
}
|
||||
if (!defined)
|
||||
return fallback_radius;
|
||||
const float radius = 0.5f * (bbox.max.cast<float>() - bbox.min.cast<float>()).norm();
|
||||
return std::isfinite(radius) && radius > 0.f ? radius : fallback_radius;
|
||||
}
|
||||
|
||||
std::optional<SurfaceGradientPreviewSettings> surface_gradient_preview_settings_for_zone(const ModelVolume &model_volume,
|
||||
const Transform3d &world_matrix,
|
||||
const TextureMappingZone &zone,
|
||||
size_t num_physical)
|
||||
size_t num_physical,
|
||||
const SurfaceGradientAnchorResolver *surface_gradient_anchor_resolver = nullptr,
|
||||
const SurfaceGradientAnchorRadiusResolver *surface_gradient_anchor_radius_resolver = nullptr)
|
||||
{
|
||||
if (!is_gradient_zone(zone))
|
||||
return std::nullopt;
|
||||
@@ -4355,17 +4450,31 @@ std::optional<SurfaceGradientPreviewSettings> surface_gradient_preview_settings_
|
||||
settings.z_min = min_pt.z();
|
||||
settings.z_max = max_pt.z();
|
||||
if (settings.linear_gradient) {
|
||||
settings.linear_start = Vec3f(settings.center.x(), settings.center.y(), settings.z_min);
|
||||
settings.linear_end = Vec3f(settings.center.x(), settings.center.y(), settings.z_max);
|
||||
if (std::optional<Vec3f> start =
|
||||
surface_gradient_anchor_world_point_for_volume(model_volume, world_matrix, zone.linear_gradient_start))
|
||||
settings.linear_start = *start;
|
||||
if (std::optional<Vec3f> end =
|
||||
surface_gradient_anchor_world_point_for_volume(model_volume, world_matrix, zone.linear_gradient_end))
|
||||
settings.linear_end = *end;
|
||||
if ((settings.linear_end - settings.linear_start).squaredNorm() <= 1e-8f) {
|
||||
settings.linear_gradient_radial = zone.linear_gradient_mode == int(TextureMappingZone::LinearGradientRadial);
|
||||
const Vec3f bbox_diagonal = max_pt - min_pt;
|
||||
const float default_radius = surface_gradient_object_radius_for_volume(model_volume,
|
||||
world_matrix,
|
||||
std::max(0.01f, 0.5f * bbox_diagonal.norm()));
|
||||
if (settings.linear_gradient_radial) {
|
||||
settings.linear_start = settings.center;
|
||||
if (std::optional<Vec3f> start =
|
||||
surface_gradient_anchor_world_point_for_volume(model_volume, world_matrix, zone.linear_gradient_start, surface_gradient_anchor_resolver))
|
||||
settings.linear_start = *start;
|
||||
settings.linear_radius_mm = surface_gradient_linear_radius_mm(zone, default_radius, surface_gradient_anchor_radius_resolver);
|
||||
settings.linear_end = settings.linear_start + Vec3f::UnitX() * settings.linear_radius_mm;
|
||||
} else {
|
||||
settings.linear_start = Vec3f(settings.center.x(), settings.center.y(), settings.z_min);
|
||||
settings.linear_end = Vec3f(settings.center.x(), settings.center.y(), settings.z_max);
|
||||
if (std::optional<Vec3f> start =
|
||||
surface_gradient_anchor_world_point_for_volume(model_volume, world_matrix, zone.linear_gradient_start, surface_gradient_anchor_resolver))
|
||||
settings.linear_start = *start;
|
||||
if (std::optional<Vec3f> end =
|
||||
surface_gradient_anchor_world_point_for_volume(model_volume, world_matrix, zone.linear_gradient_end, surface_gradient_anchor_resolver))
|
||||
settings.linear_end = *end;
|
||||
if ((settings.linear_end - settings.linear_start).squaredNorm() <= 1e-8f) {
|
||||
settings.linear_start = Vec3f(settings.center.x(), settings.center.y(), settings.z_min);
|
||||
settings.linear_end = Vec3f(settings.center.x(), settings.center.y(), settings.z_max);
|
||||
}
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
@@ -4509,12 +4618,14 @@ void set_surface_gradient_preview_uniforms(GLShaderProgram &shader, const Surfac
|
||||
shader.set_uniform("gradient_clockwise", settings == nullptr || settings->clockwise);
|
||||
shader.set_uniform("gradient_fade_mode", settings != nullptr ? settings->fade_mode : int(TextureMappingZone::OffsetFadeNone));
|
||||
shader.set_uniform("gradient_linear_mode", settings != nullptr && settings->linear_gradient);
|
||||
shader.set_uniform("gradient_linear_radial_mode", settings != nullptr && settings->linear_gradient_radial);
|
||||
const Vec3f center = settings != nullptr ? settings->center : Vec3f::Zero();
|
||||
shader.set_uniform("gradient_center", center);
|
||||
shader.set_uniform("gradient_z_min", settings != nullptr ? settings->z_min : 0.f);
|
||||
shader.set_uniform("gradient_z_max", settings != nullptr ? settings->z_max : 0.f);
|
||||
shader.set_uniform("gradient_linear_start", settings != nullptr ? settings->linear_start : Vec3f::Zero());
|
||||
shader.set_uniform("gradient_linear_end", settings != nullptr ? settings->linear_end : Vec3f::UnitZ());
|
||||
shader.set_uniform("gradient_linear_radius_mm", settings != nullptr ? settings->linear_radius_mm : 1.f);
|
||||
const size_t lut_count = settings == nullptr ? size_t(0) :
|
||||
std::min(settings->linear_gradient_lut_colors.size(), k_surface_gradient_preview_lut_size);
|
||||
shader.set_uniform("gradient_linear_lut_count", int(lut_count));
|
||||
@@ -5085,6 +5196,10 @@ static void texture_preview_mix_zone_baked_model_settings(size_t &signature,
|
||||
signature_mix(std::hash<int>{}(zone.preview_limit_resolution ? 1 : 0));
|
||||
signature_mix_float(zone.contrast_pct, 100.f);
|
||||
signature_mix_float(zone.tone_gamma);
|
||||
signature_mix(std::hash<int>{}(zone.linear_gradient_mode));
|
||||
signature_mix_float(zone.linear_gradient_radius_mm, 1000.f);
|
||||
signature_mix(std::hash<int>{}(zone.linear_gradient_radius_percent ? 1 : 0));
|
||||
signature_mix_float(zone.linear_gradient_radius_pct, 1000.f);
|
||||
for (const float strength_pct : zone.filament_strengths_pct)
|
||||
signature_mix_float(strength_pct, 100.f);
|
||||
for (const float minimum_offset_pct : zone.filament_minimum_offsets_pct)
|
||||
@@ -5351,7 +5466,9 @@ void render_model_vertex_color_preview_models(
|
||||
const std::array<float, 4> &print_volume_xy,
|
||||
const std::array<float, 2> &print_volume_z,
|
||||
bool opaque,
|
||||
const ModelVolume *model_volume)
|
||||
const ModelVolume *model_volume,
|
||||
const SurfaceGradientAnchorResolver *surface_gradient_anchor_resolver,
|
||||
const SurfaceGradientAnchorRadiusResolver *surface_gradient_anchor_radius_resolver)
|
||||
{
|
||||
if (models.empty() || colors.size() != models.size() || filament_ids.size() != models.size())
|
||||
return;
|
||||
@@ -5403,7 +5520,7 @@ void render_model_vertex_color_preview_models(
|
||||
if (model_volume == nullptr || gradient_shader == nullptr)
|
||||
continue;
|
||||
const std::optional<SurfaceGradientPreviewSettings> settings =
|
||||
surface_gradient_preview_settings_for_zone(*model_volume, model_matrix, *zone, num_physical);
|
||||
surface_gradient_preview_settings_for_zone(*model_volume, model_matrix, *zone, num_physical, surface_gradient_anchor_resolver, surface_gradient_anchor_radius_resolver);
|
||||
if (!settings && !invalid)
|
||||
continue;
|
||||
if (!use_shader(gradient_shader))
|
||||
|
||||
@@ -6,9 +6,12 @@
|
||||
|
||||
#include "libslic3r/Color.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/TextureMapping.hpp"
|
||||
#include "libslic3r/TriangleSelector.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -16,6 +19,9 @@ namespace Slic3r {
|
||||
|
||||
class TextureMappingManager;
|
||||
|
||||
using SurfaceGradientAnchorResolver = std::function<std::optional<Vec3f>(const TextureMappingZone::LinearGradientAnchor &)>;
|
||||
using SurfaceGradientAnchorRadiusResolver = std::function<std::optional<float>(const TextureMappingZone::LinearGradientAnchor &)>;
|
||||
|
||||
bool build_mmu_texture_preview_models(
|
||||
const ModelVolume &model_volume,
|
||||
const std::vector<std::vector<TriangleSelector::FacetStateTriangle>> &triangles_per_type,
|
||||
@@ -149,7 +155,9 @@ void render_model_vertex_color_preview_models(
|
||||
const std::array<float, 4> &print_volume_xy = std::array<float, 4>{ 0.f, 0.f, 0.f, 0.f },
|
||||
const std::array<float, 2> &print_volume_z = std::array<float, 2>{ 0.f, 0.f },
|
||||
bool opaque = false,
|
||||
const ModelVolume *model_volume = nullptr);
|
||||
const ModelVolume *model_volume = nullptr,
|
||||
const SurfaceGradientAnchorResolver *surface_gradient_anchor_resolver = nullptr,
|
||||
const SurfaceGradientAnchorRadiusResolver *surface_gradient_anchor_radius_resolver = nullptr);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
@@ -981,7 +982,8 @@ static std::vector<wxString> texture_mapping_channel_labels(int filament_color_m
|
||||
static wxString texture_mapping_summary(const TextureMappingZone &zone, size_t num_physical)
|
||||
{
|
||||
const bool raw_offset = zone.is_image_texture() && zone.texture_mapping_mode == int(TextureMappingZone::TextureMappingRawValues);
|
||||
wxString summary = zone.is_linear_gradient() ? _L("Linear Gradient") :
|
||||
wxString summary = zone.is_radial_linear_gradient() ? _L("Radial Gradient") :
|
||||
zone.is_linear_gradient() ? _L("Linear Gradient") :
|
||||
zone.is_2d_gradient() ? _L("2D Gradient") :
|
||||
from_u8(TextureMappingManager::filament_color_mode_name(zone.filament_color_mode));
|
||||
if (!zone.is_surface_gradient() && summary == "any")
|
||||
@@ -1004,6 +1006,8 @@ static wxString texture_mapping_summary(const TextureMappingZone &zone, size_t n
|
||||
|
||||
static wxString texture_mapping_menu_label(const TextureMappingZone &zone)
|
||||
{
|
||||
if (zone.is_radial_linear_gradient())
|
||||
return _L("Texture Mapping Radial Gradient");
|
||||
if (zone.is_linear_gradient())
|
||||
return _L("Texture Mapping Linear Gradient");
|
||||
if (zone.is_2d_gradient())
|
||||
@@ -1050,12 +1054,14 @@ public:
|
||||
void set_data(const std::vector<wxColour> &palette,
|
||||
const std::vector<unsigned int> &component_ids,
|
||||
const wxColour &fallback,
|
||||
bool linear_gradient = false)
|
||||
bool linear_gradient = false,
|
||||
bool radial_gradient = false)
|
||||
{
|
||||
m_palette = palette;
|
||||
m_component_ids = component_ids;
|
||||
m_fallback = fallback.IsOk() ? fallback : wxColour("#26A69A");
|
||||
m_linear_gradient = linear_gradient;
|
||||
m_radial_gradient = radial_gradient;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
@@ -1081,16 +1087,32 @@ private:
|
||||
if (m_linear_gradient && m_component_ids.size() >= 2) {
|
||||
const wxColour start = color_for(m_component_ids[0]);
|
||||
const wxColour end = color_for(m_component_ids[1]);
|
||||
const int h = std::max(1, rect.GetHeight());
|
||||
for (int y = 0; y < h; ++y) {
|
||||
const double t = h <= 1 ? 0.0 : double(h - 1 - y) / double(h - 1);
|
||||
const auto mix = [t](unsigned char a, unsigned char b) {
|
||||
return static_cast<unsigned char>(std::lround(double(a) * (1.0 - t) + double(b) * t));
|
||||
};
|
||||
dc.SetBrush(wxBrush(wxColour(mix(start.Red(), end.Red()),
|
||||
mix(start.Green(), end.Green()),
|
||||
mix(start.Blue(), end.Blue()))));
|
||||
dc.DrawRectangle(rect.GetLeft(), rect.GetTop() + y, rect.GetWidth(), 1);
|
||||
auto mix_channel = [](double t, unsigned char a, unsigned char b) {
|
||||
return static_cast<unsigned char>(std::lround(double(a) * (1.0 - t) + double(b) * t));
|
||||
};
|
||||
if (m_radial_gradient) {
|
||||
const double cx = double(rect.GetLeft()) + 0.5 * double(rect.GetWidth() - 1);
|
||||
const double cy = double(rect.GetTop()) + 0.5 * double(rect.GetHeight() - 1);
|
||||
const double radius = std::max(1.0, std::hypot(0.5 * double(rect.GetWidth()), 0.5 * double(rect.GetHeight())));
|
||||
for (int y = rect.GetTop(); y <= rect.GetBottom(); ++y) {
|
||||
for (int x = rect.GetLeft(); x <= rect.GetRight(); ++x) {
|
||||
const double t = std::clamp(std::hypot(double(x) - cx, double(y) - cy) / radius, 0.0, 1.0);
|
||||
dc.SetPen(wxPen(wxColour(mix_channel(t, start.Red(), end.Red()),
|
||||
mix_channel(t, start.Green(), end.Green()),
|
||||
mix_channel(t, start.Blue(), end.Blue()))));
|
||||
dc.DrawPoint(x, y);
|
||||
}
|
||||
}
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
} else {
|
||||
const int h = std::max(1, rect.GetHeight());
|
||||
for (int y = 0; y < h; ++y) {
|
||||
const double t = h <= 1 ? 0.0 : double(h - 1 - y) / double(h - 1);
|
||||
dc.SetBrush(wxBrush(wxColour(mix_channel(t, start.Red(), end.Red()),
|
||||
mix_channel(t, start.Green(), end.Green()),
|
||||
mix_channel(t, start.Blue(), end.Blue()))));
|
||||
dc.DrawRectangle(rect.GetLeft(), rect.GetTop() + y, rect.GetWidth(), 1);
|
||||
}
|
||||
}
|
||||
} else if (!m_component_ids.empty()) {
|
||||
const int slots = int(m_component_ids.size());
|
||||
@@ -1108,6 +1130,7 @@ private:
|
||||
std::vector<unsigned int> m_component_ids;
|
||||
wxColour m_fallback {wxColour("#26A69A")};
|
||||
bool m_linear_gradient { false };
|
||||
bool m_radial_gradient { false };
|
||||
};
|
||||
|
||||
class TextureMappingNumberSwatch : public wxPanel
|
||||
@@ -2690,6 +2713,7 @@ struct Sidebar::priv
|
||||
wxStaticLine* m_staticline2;
|
||||
StaticBox* m_panel_texture_mapping_title = nullptr;
|
||||
wxScrolledWindow* m_panel_texture_mapping_content = nullptr;
|
||||
wxPanel* m_panel_texture_mapping_resize_handle = nullptr;
|
||||
wxBoxSizer* m_sizer_texture_mapping_content = nullptr;
|
||||
ScalableButton* m_texture_mapping_icon = nullptr;
|
||||
wxStaticText* m_staticText_texture_mapping = nullptr;
|
||||
@@ -2697,6 +2721,11 @@ struct Sidebar::priv
|
||||
std::unordered_set<size_t> m_expanded_texture_mapping_rows;
|
||||
int m_texture_mapping_advanced_options_tab = 0;
|
||||
bool m_texture_mapping_filament_strength_offsets_expanded = false;
|
||||
int m_texture_mapping_base_height = 0;
|
||||
int m_texture_mapping_user_height = 0;
|
||||
bool m_texture_mapping_resizing = false;
|
||||
int m_texture_mapping_resize_start_screen_y = 0;
|
||||
int m_texture_mapping_resize_start_height = 0;
|
||||
wxPanel* m_panel_project_title;
|
||||
ScalableButton* m_filament_icon = nullptr;
|
||||
Button * m_flushing_volume_btn = nullptr;
|
||||
@@ -2737,6 +2766,7 @@ struct Sidebar::priv
|
||||
bool sync_extruder_list(bool &only_external_material);
|
||||
bool switch_diameter(bool single);
|
||||
void update_sync_status(const MachineObject* obj);
|
||||
void apply_texture_mapping_area_height(Sidebar *sidebar);
|
||||
|
||||
#ifdef _WIN32
|
||||
wxString btn_reslice_tip;
|
||||
@@ -2840,6 +2870,27 @@ Sidebar::priv::~priv()
|
||||
#endif
|
||||
}
|
||||
|
||||
void Sidebar::priv::apply_texture_mapping_area_height(Sidebar *sidebar)
|
||||
{
|
||||
if (sidebar == nullptr || m_panel_texture_mapping_content == nullptr || m_panel_texture_mapping_content->GetSizer() == nullptr)
|
||||
return;
|
||||
|
||||
m_panel_texture_mapping_content->Layout();
|
||||
m_panel_texture_mapping_content->FitInside();
|
||||
|
||||
const int default_max_height = sidebar->FromDIP(260);
|
||||
wxSize min_size = m_panel_texture_mapping_content->GetSizer()->GetMinSize();
|
||||
m_texture_mapping_base_height = std::max(sidebar->FromDIP(1), std::min(min_size.y, default_max_height));
|
||||
|
||||
const int requested_height = m_texture_mapping_user_height > 0 ?
|
||||
std::max(m_texture_mapping_user_height, m_texture_mapping_base_height) :
|
||||
m_texture_mapping_base_height;
|
||||
const int visible_height = std::max(sidebar->FromDIP(1), std::min(min_size.y, requested_height));
|
||||
|
||||
m_panel_texture_mapping_content->SetMaxSize(wxSize(-1, requested_height));
|
||||
m_panel_texture_mapping_content->SetMinSize(wxSize(-1, visible_height));
|
||||
}
|
||||
|
||||
void Sidebar::priv::show_preset_comboboxes()
|
||||
{
|
||||
const bool showSLA = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA;
|
||||
@@ -4303,13 +4354,6 @@ Sidebar::Sidebar(Plater *parent)
|
||||
p->m_panel_filament_title = new StaticBox(p->scrolled, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxBORDER_NONE);
|
||||
p->m_panel_filament_title->SetBackgroundColor(title_bg);
|
||||
p->m_panel_filament_title->SetBackgroundColor2(0xF1F1F1);
|
||||
p->m_panel_filament_title->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent &e) {
|
||||
if (e.GetPosition().x > (p->m_flushing_volume_btn->IsShown()
|
||||
? p->m_flushing_volume_btn->GetPosition().x : (p->m_bpButton_add_filament->GetPosition().x - FromDIP(30)))) // ORCA exclude area of del button from titlebar collapse/expand feature to fix undesired collapse when user spams del filament button
|
||||
return;
|
||||
p->m_panel_filament_content->Show(!p->m_panel_filament_content->IsShown());
|
||||
m_scrolled_sizer->Layout();
|
||||
});
|
||||
|
||||
wxBoxSizer* bSizer39;
|
||||
bSizer39 = new wxBoxSizer( wxHORIZONTAL );
|
||||
@@ -4397,6 +4441,7 @@ Sidebar::Sidebar(Plater *parent)
|
||||
|
||||
bSizer39->Add(set_btn, 0, wxALIGN_CENTER | wxLEFT, FromDIP(SidebarProps::WideSpacing()));
|
||||
bSizer39->AddSpacer(FromDIP(SidebarProps::TitlebarMargin()));
|
||||
p->m_panel_filament_title->Layout();
|
||||
|
||||
// add filament content
|
||||
p->m_panel_filament_content = new wxScrolledWindow( p->scrolled, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
@@ -4428,6 +4473,43 @@ Sidebar::Sidebar(Plater *parent)
|
||||
update_filaments_area_height(); // ORCA
|
||||
|
||||
scrolled_sizer->Add(p->m_panel_filament_content, 0, wxEXPAND | wxTOP | wxBOTTOM, FromDIP(SidebarProps::ContentMarginV())); // ORCA use vertical margin on parent otherwise it shows scrollbar even on 1 filament
|
||||
|
||||
auto toggle_filament_content = [this]() {
|
||||
if (p->m_panel_filament_content == nullptr)
|
||||
return;
|
||||
p->m_panel_filament_content->Show(!p->m_panel_filament_content->IsShown());
|
||||
m_scrolled_sizer->Layout();
|
||||
};
|
||||
auto filament_title_button_hit = [this](const wxPoint &pos) {
|
||||
for (wxWindow *window : {static_cast<wxWindow *>(p->m_filament_icon),
|
||||
static_cast<wxWindow *>(p->m_flushing_volume_btn),
|
||||
static_cast<wxWindow *>(p->m_bpButton_del_filament),
|
||||
static_cast<wxWindow *>(p->m_bpButton_add_filament),
|
||||
static_cast<wxWindow *>(p->m_bpButton_ams_filament),
|
||||
static_cast<wxWindow *>(p->m_bpButton_set_filament)}) {
|
||||
if (window == nullptr || !window->IsShown())
|
||||
continue;
|
||||
wxRect rect(window->GetPosition(), window->GetSize());
|
||||
rect.Inflate(FromDIP(6), FromDIP(4));
|
||||
if (rect.Contains(pos))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
auto handle_filament_title_click = [this, toggle_filament_content, filament_title_button_hit](wxMouseEvent &e) {
|
||||
wxWindow *event_window = dynamic_cast<wxWindow *>(e.GetEventObject());
|
||||
wxPoint title_pos = e.GetPosition();
|
||||
if (event_window != nullptr && event_window != p->m_panel_filament_title)
|
||||
title_pos = p->m_panel_filament_title->ScreenToClient(event_window->ClientToScreen(e.GetPosition()));
|
||||
if (filament_title_button_hit(title_pos))
|
||||
return;
|
||||
toggle_filament_content();
|
||||
};
|
||||
p->m_panel_filament_title->Bind(wxEVT_LEFT_UP, handle_filament_title_click);
|
||||
p->m_staticText_filament_settings->Bind(wxEVT_LEFT_UP, handle_filament_title_click);
|
||||
p->m_filament_icon->Bind(wxEVT_BUTTON, [toggle_filament_content](wxCommandEvent &) {
|
||||
toggle_filament_content();
|
||||
});
|
||||
}
|
||||
|
||||
{
|
||||
@@ -4516,6 +4598,44 @@ Sidebar::Sidebar(Plater *parent)
|
||||
p->m_panel_texture_mapping_content->SetSizer(p->m_sizer_texture_mapping_content);
|
||||
p->m_panel_texture_mapping_content->Layout();
|
||||
scrolled_sizer->Add(p->m_panel_texture_mapping_content, 0, wxEXPAND, 0);
|
||||
p->m_panel_texture_mapping_resize_handle = new wxPanel(p->scrolled, wxID_ANY, wxDefaultPosition, wxSize(-1, FromDIP(5)), wxBORDER_NONE);
|
||||
p->m_panel_texture_mapping_resize_handle->SetMinSize(wxSize(-1, FromDIP(5)));
|
||||
p->m_panel_texture_mapping_resize_handle->SetMaxSize(wxSize(-1, FromDIP(5)));
|
||||
p->m_panel_texture_mapping_resize_handle->SetCursor(wxCursor(wxCURSOR_SIZENS));
|
||||
p->m_panel_texture_mapping_resize_handle->SetBackgroundColour(p->m_panel_texture_mapping_content->GetBackgroundColour());
|
||||
scrolled_sizer->Add(p->m_panel_texture_mapping_resize_handle, 0, wxEXPAND, 0);
|
||||
|
||||
auto resize_texture_mapping_to = [this](int height) {
|
||||
p->m_texture_mapping_user_height = std::max(p->m_texture_mapping_base_height, height);
|
||||
p->apply_texture_mapping_area_height(this);
|
||||
m_scrolled_sizer->Layout();
|
||||
Layout();
|
||||
};
|
||||
p->m_panel_texture_mapping_resize_handle->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) {
|
||||
if (p->m_panel_texture_mapping_content == nullptr)
|
||||
return;
|
||||
p->m_texture_mapping_resizing = true;
|
||||
p->m_texture_mapping_resize_start_screen_y = p->m_panel_texture_mapping_resize_handle->ClientToScreen(e.GetPosition()).y;
|
||||
p->m_texture_mapping_resize_start_height = std::max(p->m_texture_mapping_user_height, p->m_texture_mapping_base_height);
|
||||
if (p->m_panel_texture_mapping_resize_handle->HasCapture() == false)
|
||||
p->m_panel_texture_mapping_resize_handle->CaptureMouse();
|
||||
});
|
||||
p->m_panel_texture_mapping_resize_handle->Bind(wxEVT_MOTION, [this, resize_texture_mapping_to](wxMouseEvent &e) {
|
||||
if (!p->m_texture_mapping_resizing) {
|
||||
e.Skip();
|
||||
return;
|
||||
}
|
||||
const int delta = p->m_panel_texture_mapping_resize_handle->ClientToScreen(e.GetPosition()).y - p->m_texture_mapping_resize_start_screen_y;
|
||||
resize_texture_mapping_to(p->m_texture_mapping_resize_start_height + delta);
|
||||
});
|
||||
p->m_panel_texture_mapping_resize_handle->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent &) {
|
||||
p->m_texture_mapping_resizing = false;
|
||||
if (p->m_panel_texture_mapping_resize_handle != nullptr && p->m_panel_texture_mapping_resize_handle->HasCapture())
|
||||
p->m_panel_texture_mapping_resize_handle->ReleaseMouse();
|
||||
});
|
||||
p->m_panel_texture_mapping_resize_handle->Bind(wxEVT_MOUSE_CAPTURE_LOST, [this](wxMouseCaptureLostEvent &) {
|
||||
p->m_texture_mapping_resizing = false;
|
||||
});
|
||||
|
||||
p->m_panel_texture_mapping_title->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent& e) {
|
||||
int button_left = p->m_panel_texture_mapping_title->GetClientSize().x;
|
||||
@@ -4523,12 +4643,16 @@ Sidebar::Sidebar(Plater *parent)
|
||||
button_left = std::min(button_left, p->m_btn_add_texture_map->GetPosition().x);
|
||||
if (e.GetPosition().x > button_left - FromDIP(12))
|
||||
return;
|
||||
p->m_panel_texture_mapping_content->Show(!p->m_panel_texture_mapping_content->IsShown());
|
||||
const bool show_content = !p->m_panel_texture_mapping_content->IsShown();
|
||||
p->m_panel_texture_mapping_content->Show(show_content);
|
||||
if (p->m_panel_texture_mapping_resize_handle != nullptr)
|
||||
p->m_panel_texture_mapping_resize_handle->Show(show_content);
|
||||
m_scrolled_sizer->Layout();
|
||||
});
|
||||
|
||||
p->m_panel_texture_mapping_title->Hide();
|
||||
p->m_panel_texture_mapping_content->Hide();
|
||||
p->m_panel_texture_mapping_resize_handle->Hide();
|
||||
}
|
||||
|
||||
{
|
||||
@@ -6167,16 +6291,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
content_sizer->Clear(true);
|
||||
content_sizer->AddSpacer(FromDIP(SidebarProps::ContentMargin()));
|
||||
auto update_texture_mapping_area_height = [this]() {
|
||||
if (p->m_panel_texture_mapping_content == nullptr || p->m_panel_texture_mapping_content->GetSizer() == nullptr)
|
||||
return;
|
||||
const int max_height = FromDIP(260);
|
||||
p->m_panel_texture_mapping_content->SetMaxSize(wxSize(-1, max_height));
|
||||
p->m_panel_texture_mapping_content->Layout();
|
||||
p->m_panel_texture_mapping_content->FitInside();
|
||||
wxSize min_size = p->m_panel_texture_mapping_content->GetSizer()->GetMinSize();
|
||||
if (min_size.y > max_height)
|
||||
min_size.y = max_height;
|
||||
p->m_panel_texture_mapping_content->SetMinSize(wxSize(-1, std::max(FromDIP(1), min_size.y)));
|
||||
p->apply_texture_mapping_area_height(this);
|
||||
};
|
||||
|
||||
if (p->m_btn_add_texture_map != nullptr)
|
||||
@@ -6185,6 +6300,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
if (num_physical < 2) {
|
||||
p->m_panel_texture_mapping_title->Hide();
|
||||
p->m_panel_texture_mapping_content->Hide();
|
||||
if (p->m_panel_texture_mapping_resize_handle != nullptr)
|
||||
p->m_panel_texture_mapping_resize_handle->Hide();
|
||||
m_scrolled_sizer->Layout();
|
||||
Layout();
|
||||
return;
|
||||
@@ -6192,6 +6309,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
|
||||
p->m_panel_texture_mapping_title->Show();
|
||||
p->m_panel_texture_mapping_content->Show();
|
||||
if (p->m_panel_texture_mapping_resize_handle != nullptr)
|
||||
p->m_panel_texture_mapping_resize_handle->Show();
|
||||
|
||||
const bool is_dark = wxGetApp().dark_mode();
|
||||
const wxColour rows_bg = is_dark ? wxColour(45, 45, 49) : wxColour(246, 248, 251);
|
||||
@@ -6200,6 +6319,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
const wxColour summary_fg = is_dark ? wxColour(182, 182, 182) : wxColour(96, 96, 96);
|
||||
const int gap = FromDIP(6);
|
||||
p->m_panel_texture_mapping_content->SetBackgroundColour(rows_bg);
|
||||
if (p->m_panel_texture_mapping_resize_handle != nullptr)
|
||||
p->m_panel_texture_mapping_resize_handle->SetBackgroundColour(rows_bg);
|
||||
|
||||
auto make_sidebar_combo = [](wxWindow *parent, const wxArrayString &choices, int selection, const wxSize &size) {
|
||||
auto *combo = new ::ComboBox(parent, wxID_ANY, wxString(), wxDefaultPosition, size, 0, nullptr, wxCB_READONLY);
|
||||
@@ -6347,6 +6468,14 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
return int(TextureMappingZone::ImageTexture);
|
||||
};
|
||||
|
||||
auto linear_gradient_mode_selection = [](const TextureMappingZone &zone) {
|
||||
return zone.linear_gradient_mode == int(TextureMappingZone::LinearGradientRadial) ? 1 : 0;
|
||||
};
|
||||
|
||||
auto linear_gradient_mode_from_selection = [](int selection) {
|
||||
return selection == 1 ? int(TextureMappingZone::LinearGradientRadial) : int(TextureMappingZone::LinearGradientLinear);
|
||||
};
|
||||
|
||||
if (visible_zone_indices.empty()) {
|
||||
auto *empty_label = new wxStaticText(p->m_panel_texture_mapping_content, wxID_ANY, _L("No texture maps yet."));
|
||||
empty_label->SetForegroundColour(summary_fg);
|
||||
@@ -6440,7 +6569,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
TextureMappingManager::effective_texture_component_ids(entry, num_physical, physical_colors) :
|
||||
texture_mapping_selected_ids(entry, num_physical),
|
||||
parse_texture_mapping_color(entry.display_color),
|
||||
entry.is_linear_gradient());
|
||||
entry.is_linear_gradient(),
|
||||
entry.is_radial_linear_gradient());
|
||||
header_sizer->Add(preview, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
row_sizer->Add(header, 0, wxEXPAND | wxTOP | wxBOTTOM, gap);
|
||||
|
||||
@@ -6462,7 +6592,8 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
TextureMappingManager::effective_texture_component_ids(zone, num_physical, physical_colors) :
|
||||
texture_mapping_selected_ids(zone, num_physical),
|
||||
parse_texture_mapping_color(zone.display_color),
|
||||
zone.is_linear_gradient());
|
||||
zone.is_linear_gradient(),
|
||||
zone.is_radial_linear_gradient());
|
||||
}
|
||||
if (swatch != nullptr)
|
||||
swatch->set_data(parse_texture_mapping_color(zone.display_color), zone_id);
|
||||
@@ -6522,7 +6653,19 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
}
|
||||
editor_sizer->Add(filaments_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
|
||||
auto *linear_gradient_row = new wxWrapSizer(wxHORIZONTAL, wxWRAPSIZER_DEFAULT_FLAGS);
|
||||
auto *linear_gradient_mode_row = new wxWrapSizer(wxHORIZONTAL, wxWRAPSIZER_DEFAULT_FLAGS);
|
||||
linear_gradient_mode_row->Add(new wxStaticText(editor, wxID_ANY, _L("Gradient mode")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
wxArrayString linear_gradient_mode_choices;
|
||||
linear_gradient_mode_choices.Add(_L("Linear"));
|
||||
linear_gradient_mode_choices.Add(_L("Radial"));
|
||||
auto *linear_gradient_mode_choice = make_sidebar_combo(editor,
|
||||
linear_gradient_mode_choices,
|
||||
linear_gradient_mode_selection(entry),
|
||||
wxSize(FromDIP(170), -1));
|
||||
linear_gradient_mode_row->Add(linear_gradient_mode_choice, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
editor_sizer->Add(linear_gradient_mode_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
|
||||
auto *linear_gradient_row = new wxBoxSizer(wxHORIZONTAL);
|
||||
linear_gradient_row->Add(new wxStaticText(editor, wxID_ANY, _L("Gradient")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
auto *start_filament_combo = make_filament_swatch_combo(editor, selected_ids.empty() ? 1 : selected_ids.front());
|
||||
auto *end_filament_combo = make_filament_swatch_combo(editor, selected_ids.size() > 1 ? selected_ids[1] : (selected_ids.empty() ? 1 : selected_ids.front()));
|
||||
@@ -6531,9 +6674,15 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
start_filament_combo->Enable(can_choose_linear_gradient_filaments);
|
||||
if (end_filament_combo != nullptr)
|
||||
end_filament_combo->Enable(can_choose_linear_gradient_filaments);
|
||||
auto *set_start_btn = new wxButton(editor, wxID_ANY, _L("Set Start"));
|
||||
auto *set_end_btn = new wxButton(editor, wxID_ANY, _L("Set End"));
|
||||
const bool entry_radial_gradient = linear_gradient_mode_selection(entry) == 1;
|
||||
auto *set_start_btn = new wxButton(editor,
|
||||
wxID_ANY,
|
||||
entry_radial_gradient ?
|
||||
(entry.linear_gradient_start.valid ? _L("Set Center") : _L("Add Center")) :
|
||||
(entry.linear_gradient_start.valid ? _L("Set Start") : _L("Add Start")));
|
||||
auto *set_end_btn = new wxButton(editor, wxID_ANY, entry.linear_gradient_end.valid ? _L("Set End") : _L("Add End"));
|
||||
auto *clear_points_btn = new wxButton(editor, wxID_ANY, _L("Clear Points"));
|
||||
clear_points_btn->Enable(entry.linear_gradient_start.valid || entry.linear_gradient_end.valid);
|
||||
::CheckBox *show_direction_arrow_chk = nullptr;
|
||||
linear_gradient_row->Add(new wxStaticText(editor, wxID_ANY, _L("Start")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2);
|
||||
linear_gradient_row->Add(start_filament_combo, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
@@ -6547,6 +6696,33 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
linear_gradient_buttons_row->Add(clear_points_btn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
editor_sizer->Add(linear_gradient_buttons_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
|
||||
auto *linear_gradient_radius_row = new wxWrapSizer(wxHORIZONTAL, wxWRAPSIZER_DEFAULT_FLAGS);
|
||||
linear_gradient_radius_row->Add(new wxStaticText(editor, wxID_ANY, _L("Radius")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
const double linear_gradient_radius_value = entry.linear_gradient_radius_percent ?
|
||||
std::clamp(double(entry.linear_gradient_radius_pct), 0.0, 100000.0) :
|
||||
std::clamp(double(entry.linear_gradient_radius_mm), 0.0, 100000.0);
|
||||
auto *linear_gradient_radius_spin = new wxSpinCtrlDouble(editor,
|
||||
wxID_ANY,
|
||||
wxEmptyString,
|
||||
wxDefaultPosition,
|
||||
wxSize(FromDIP(96), -1),
|
||||
wxSP_ARROW_KEYS | wxALIGN_RIGHT | wxTE_PROCESS_ENTER,
|
||||
0.0,
|
||||
100000.0,
|
||||
linear_gradient_radius_value,
|
||||
1.0);
|
||||
linear_gradient_radius_spin->SetDigits(2);
|
||||
::CheckBox *linear_gradient_radius_percent_chk = nullptr;
|
||||
auto *linear_gradient_radius_unit_label = new wxStaticText(editor, wxID_ANY, entry.linear_gradient_radius_percent ? _L("%") : _L("mm"));
|
||||
linear_gradient_radius_row->Add(linear_gradient_radius_spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2);
|
||||
linear_gradient_radius_row->Add(linear_gradient_radius_unit_label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
auto *linear_gradient_radius_percent_row = make_sidebar_checkbox_row(editor,
|
||||
linear_gradient_radius_percent_chk,
|
||||
_L("Percent"),
|
||||
entry.linear_gradient_radius_percent);
|
||||
linear_gradient_radius_row->Add(linear_gradient_radius_percent_row, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
editor_sizer->Add(linear_gradient_radius_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
|
||||
auto *show_direction_arrow_row = make_sidebar_checkbox_row(editor,
|
||||
show_direction_arrow_chk,
|
||||
_L("Show Direction Arrow"),
|
||||
@@ -6555,24 +6731,40 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
|
||||
wxWeakRef<wxButton> set_start_btn_ref(set_start_btn);
|
||||
wxWeakRef<wxButton> set_end_btn_ref(set_end_btn);
|
||||
wxWeakRef<wxButton> clear_points_btn_ref(clear_points_btn);
|
||||
wxWindowRef editor_ref(editor);
|
||||
wxWindowRef row_ref(row);
|
||||
auto set_linear_gradient_picker_button_labels = [this,
|
||||
zone_index,
|
||||
mgr_ptr,
|
||||
set_start_btn_ref,
|
||||
set_end_btn_ref,
|
||||
clear_points_btn_ref,
|
||||
linear_gradient_mode_choice,
|
||||
editor_ref,
|
||||
row_ref,
|
||||
update_texture_mapping_area_height](GLGizmoTextureGradientPointPicker::Target active_target) {
|
||||
const TextureMappingZone *zone = mgr_ptr != nullptr && zone_index < mgr_ptr->zones().size() ? &mgr_ptr->zones()[zone_index] : nullptr;
|
||||
const bool radial_gradient = linear_gradient_mode_choice != nullptr && linear_gradient_mode_choice->GetSelection() == 1;
|
||||
const bool has_start = zone != nullptr && zone->linear_gradient_start.valid;
|
||||
const bool has_end = zone != nullptr && zone->linear_gradient_end.valid;
|
||||
if (wxButton *button = set_start_btn_ref.get()) {
|
||||
button->SetLabel(active_target == GLGizmoTextureGradientPointPicker::Target::Start ? _L("Cancel selection") : _L("Set Start"));
|
||||
const wxString inactive_label = radial_gradient ?
|
||||
(has_start ? _L("Set Center") : _L("Add Center")) :
|
||||
(has_start ? _L("Set Start") : _L("Add Start"));
|
||||
button->SetLabel(active_target == GLGizmoTextureGradientPointPicker::Target::Start ? _L("Cancel selection") : inactive_label);
|
||||
button->InvalidateBestSize();
|
||||
button->Fit();
|
||||
}
|
||||
if (wxButton *button = set_end_btn_ref.get()) {
|
||||
button->SetLabel(active_target == GLGizmoTextureGradientPointPicker::Target::End ? _L("Cancel selection") : _L("Set End"));
|
||||
button->SetLabel(active_target == GLGizmoTextureGradientPointPicker::Target::End ? _L("Cancel selection") : (has_end ? _L("Set End") : _L("Add End")));
|
||||
button->Show(!radial_gradient);
|
||||
button->Enable(!radial_gradient);
|
||||
button->InvalidateBestSize();
|
||||
button->Fit();
|
||||
}
|
||||
if (wxButton *button = clear_points_btn_ref.get())
|
||||
button->Enable(has_start || has_end);
|
||||
if (wxWindow *window = editor_ref.get())
|
||||
window->Layout();
|
||||
if (wxWindow *window = row_ref.get())
|
||||
@@ -6620,8 +6812,9 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
editor_sizer->Add(button_row, 0, wxEXPAND | wxALL, gap);
|
||||
|
||||
auto apply_controls = [zone_index, mgr_ptr, num_physical, filament_checks, surface_choice,
|
||||
start_filament_combo, end_filament_combo,
|
||||
linear_gradient_filament_ids, surface_pattern_from_selection, mode_choice, preview_colors_chk,
|
||||
start_filament_combo, end_filament_combo, linear_gradient_mode_choice, linear_gradient_radius_spin,
|
||||
linear_gradient_radius_percent_chk,
|
||||
linear_gradient_filament_ids, surface_pattern_from_selection, linear_gradient_mode_from_selection, mode_choice, preview_colors_chk,
|
||||
show_direction_arrow_chk, contrast_spin, apply_zone](int changed_side = 0) {
|
||||
if (mgr_ptr == nullptr)
|
||||
return;
|
||||
@@ -6645,6 +6838,19 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.component_ids = encode_texture_mapping_component_ids(ids);
|
||||
updated.component_a = ids.empty() ? 1 : ids.front();
|
||||
updated.component_b = ids.size() > 1 ? ids[1] : updated.component_a;
|
||||
updated.linear_gradient_mode = linear_gradient_mode_from_selection(linear_gradient_mode_choice != nullptr ?
|
||||
linear_gradient_mode_choice->GetSelection() :
|
||||
0);
|
||||
updated.linear_gradient_radius_percent = linear_gradient_radius_percent_chk != nullptr ?
|
||||
linear_gradient_radius_percent_chk->GetValue() :
|
||||
updated.linear_gradient_radius_percent;
|
||||
if (linear_gradient_radius_spin != nullptr) {
|
||||
const float radius_value = std::clamp(float(linear_gradient_radius_spin->GetValue()), 0.f, 100000.f);
|
||||
if (updated.linear_gradient_radius_percent)
|
||||
updated.linear_gradient_radius_pct = radius_value;
|
||||
else
|
||||
updated.linear_gradient_radius_mm = radius_value;
|
||||
}
|
||||
updated.filament_color_mode = mode_choice != nullptr ?
|
||||
texture_mapping_color_mode_from_selection(mode_choice->GetSelection(), updated.filament_color_mode) :
|
||||
updated.filament_color_mode;
|
||||
@@ -6666,13 +6872,16 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
}
|
||||
evt.Skip();
|
||||
});
|
||||
auto update_pattern_visibility = [this, editor_sizer, filaments_row, linear_gradient_row, linear_gradient_buttons_row, show_direction_arrow_row, mode_row, contrast_row, preview_colors_row, offset_btn, advanced_btn, surface_choice, row, editor, update_texture_mapping_area_height]() {
|
||||
auto update_pattern_visibility = [this, editor_sizer, filaments_row, linear_gradient_mode_row, linear_gradient_mode_choice, linear_gradient_row, linear_gradient_buttons_row, linear_gradient_radius_row, show_direction_arrow_row, mode_row, contrast_row, preview_colors_row, offset_btn, advanced_btn, surface_choice, row, editor, update_texture_mapping_area_height, set_linear_gradient_picker_button_labels]() {
|
||||
const int selection = surface_choice == nullptr ? 0 : surface_choice->GetSelection();
|
||||
const bool image_texture = selection == 0;
|
||||
const bool linear_gradient = selection == 1;
|
||||
const bool radial_gradient = linear_gradient && linear_gradient_mode_choice != nullptr && linear_gradient_mode_choice->GetSelection() == 1;
|
||||
editor_sizer->Show(filaments_row, !linear_gradient, true);
|
||||
editor_sizer->Show(linear_gradient_mode_row, linear_gradient, true);
|
||||
editor_sizer->Show(linear_gradient_row, linear_gradient, true);
|
||||
editor_sizer->Show(linear_gradient_buttons_row, linear_gradient, true);
|
||||
editor_sizer->Show(linear_gradient_radius_row, radial_gradient, true);
|
||||
editor_sizer->Show(show_direction_arrow_row, linear_gradient, true);
|
||||
editor_sizer->Show(mode_row, image_texture, true);
|
||||
editor_sizer->Show(contrast_row, image_texture, true);
|
||||
@@ -6681,6 +6890,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
offset_btn->Show(selection == 2);
|
||||
if (advanced_btn != nullptr)
|
||||
advanced_btn->Show();
|
||||
set_linear_gradient_picker_button_labels(GLGizmoTextureGradientPointPicker::Target::None);
|
||||
editor->Layout();
|
||||
row->Layout();
|
||||
update_texture_mapping_area_height();
|
||||
@@ -6693,6 +6903,11 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
update_pattern_visibility();
|
||||
apply_controls();
|
||||
});
|
||||
if (linear_gradient_mode_choice != nullptr)
|
||||
linear_gradient_mode_choice->Bind(wxEVT_COMBOBOX, [update_pattern_visibility, apply_controls](wxCommandEvent &) {
|
||||
update_pattern_visibility();
|
||||
apply_controls();
|
||||
});
|
||||
for (::CheckBox *chk : filament_checks)
|
||||
if (chk != nullptr)
|
||||
chk->Bind(wxEVT_TOGGLEBUTTON, [apply_controls](wxCommandEvent &evt) {
|
||||
@@ -6712,7 +6927,11 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
filament_checks,
|
||||
start_filament_combo,
|
||||
end_filament_combo,
|
||||
linear_gradient_mode_choice,
|
||||
linear_gradient_radius_spin,
|
||||
linear_gradient_radius_percent_chk,
|
||||
linear_gradient_filament_ids,
|
||||
linear_gradient_mode_from_selection,
|
||||
mode_choice,
|
||||
surface_choice,
|
||||
preview_colors_chk,
|
||||
@@ -6750,6 +6969,19 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.component_ids = encode_texture_mapping_component_ids(ids);
|
||||
updated.component_a = ids.empty() ? 1 : ids.front();
|
||||
updated.component_b = ids.size() > 1 ? ids[1] : updated.component_a;
|
||||
updated.linear_gradient_mode = linear_gradient_mode_from_selection(linear_gradient_mode_choice != nullptr ?
|
||||
linear_gradient_mode_choice->GetSelection() :
|
||||
0);
|
||||
updated.linear_gradient_radius_percent = linear_gradient_radius_percent_chk != nullptr ?
|
||||
linear_gradient_radius_percent_chk->GetValue() :
|
||||
updated.linear_gradient_radius_percent;
|
||||
if (linear_gradient_radius_spin != nullptr) {
|
||||
const float radius_value = std::clamp(float(linear_gradient_radius_spin->GetValue()), 0.f, 100000.f);
|
||||
if (updated.linear_gradient_radius_percent)
|
||||
updated.linear_gradient_radius_pct = radius_value;
|
||||
else
|
||||
updated.linear_gradient_radius_mm = radius_value;
|
||||
}
|
||||
updated.filament_color_mode = mode_choice != nullptr ?
|
||||
texture_mapping_color_mode_from_selection(mode_choice->GetSelection(), updated.filament_color_mode) :
|
||||
updated.filament_color_mode;
|
||||
@@ -6791,6 +7023,46 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
apply_controls();
|
||||
evt.Skip();
|
||||
});
|
||||
auto update_linear_gradient_radius_unit = [linear_gradient_radius_percent_chk, linear_gradient_radius_unit_label]() {
|
||||
if (linear_gradient_radius_unit_label != nullptr)
|
||||
linear_gradient_radius_unit_label->SetLabel(linear_gradient_radius_percent_chk != nullptr && linear_gradient_radius_percent_chk->GetValue() ? _L("%") : _L("mm"));
|
||||
};
|
||||
if (linear_gradient_radius_percent_chk != nullptr)
|
||||
linear_gradient_radius_percent_chk->Bind(wxEVT_TOGGLEBUTTON, [zone_index,
|
||||
mgr_ptr,
|
||||
linear_gradient_radius_spin,
|
||||
linear_gradient_radius_percent_chk,
|
||||
update_linear_gradient_radius_unit,
|
||||
apply_controls](wxCommandEvent &evt) {
|
||||
if (linear_gradient_radius_spin != nullptr && mgr_ptr != nullptr && zone_index < mgr_ptr->zones().size()) {
|
||||
const TextureMappingZone &zone = mgr_ptr->zones()[zone_index];
|
||||
const double value = linear_gradient_radius_percent_chk->GetValue() ?
|
||||
std::clamp(double(zone.linear_gradient_radius_pct), 0.0, 100000.0) :
|
||||
std::clamp(double(zone.linear_gradient_radius_mm), 0.0, 100000.0);
|
||||
linear_gradient_radius_spin->SetValue(value);
|
||||
}
|
||||
update_linear_gradient_radius_unit();
|
||||
apply_controls();
|
||||
evt.Skip();
|
||||
});
|
||||
if (linear_gradient_radius_spin != nullptr) {
|
||||
linear_gradient_radius_spin->Bind(wxEVT_SPINCTRLDOUBLE, [apply_controls](wxSpinDoubleEvent &) { apply_controls(); });
|
||||
linear_gradient_radius_spin->Bind(wxEVT_TEXT_ENTER, [apply_controls](wxCommandEvent &) { apply_controls(); });
|
||||
linear_gradient_radius_spin->Bind(wxEVT_KILL_FOCUS, [apply_controls](wxFocusEvent &evt) {
|
||||
apply_controls();
|
||||
evt.Skip();
|
||||
});
|
||||
linear_gradient_radius_spin->Bind(wxEVT_CHAR_HOOK, [linear_gradient_radius_spin, apply_controls](wxKeyEvent &evt) {
|
||||
const int key = evt.GetKeyCode();
|
||||
if (key == WXK_UP || key == WXK_NUMPAD_UP || key == WXK_DOWN || key == WXK_NUMPAD_DOWN) {
|
||||
const double direction = (key == WXK_UP || key == WXK_NUMPAD_UP) ? 1.0 : -1.0;
|
||||
linear_gradient_radius_spin->SetValue(std::clamp(linear_gradient_radius_spin->GetValue() + direction, 0.0, 100000.0));
|
||||
apply_controls();
|
||||
return;
|
||||
}
|
||||
evt.Skip();
|
||||
});
|
||||
}
|
||||
contrast_spin->Bind(wxEVT_SPINCTRL, [apply_controls](wxCommandEvent &) { apply_controls(); });
|
||||
contrast_spin->Bind(wxEVT_TEXT_ENTER, [apply_controls](wxCommandEvent &) { apply_controls(); });
|
||||
contrast_spin->Bind(wxEVT_KILL_FOCUS, [apply_controls](wxFocusEvent &evt) {
|
||||
@@ -6859,9 +7131,12 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
apply_linear_gradient_pick,
|
||||
make_linear_gradient_anchor,
|
||||
set_config_string,
|
||||
linear_gradient_mode_choice,
|
||||
set_linear_gradient_picker_button_labels](bool start_point) {
|
||||
if (p->plater == nullptr)
|
||||
return;
|
||||
if (!start_point && linear_gradient_mode_choice != nullptr && linear_gradient_mode_choice->GetSelection() == 1)
|
||||
return;
|
||||
GLCanvas3D *canvas = p->plater->get_current_canvas3D(true);
|
||||
if (canvas == nullptr)
|
||||
return;
|
||||
@@ -6884,6 +7159,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
if (mgr_ptr == nullptr || zone_index >= mgr_ptr->zones().size())
|
||||
return;
|
||||
const TextureMappingZone original = mgr_ptr->zones()[zone_index];
|
||||
picker->set_radial_mode(original.linear_gradient_mode == int(TextureMappingZone::LinearGradientRadial));
|
||||
const std::string original_serialized = serialize_texture_mapping_manager(mgr_ptr);
|
||||
TextureMappingZone active_preview = original;
|
||||
active_preview.surface_pattern = int(TextureMappingZone::LinearGradient);
|
||||
|
||||
Reference in New Issue
Block a user