Update scene preview when 2D gradient settings are being changed
This commit is contained in:
@@ -18,6 +18,7 @@ uniform bool invalid_texture_mapping;
|
||||
uniform PrintVolumeDetection print_volume;
|
||||
|
||||
uniform int gradient_component_count;
|
||||
uniform vec3 gradient_base_color;
|
||||
uniform vec3 gradient_component_colors[MAX_GRADIENT_COMPONENTS];
|
||||
uniform float gradient_distances_mm[MAX_GRADIENT_COMPONENTS];
|
||||
uniform float gradient_angles_deg[MAX_GRADIENT_COMPONENTS];
|
||||
@@ -96,7 +97,7 @@ float offset_fade_factor(int fade_mode, float progress01)
|
||||
if (fade_mode == 4)
|
||||
return abs(2.0 * p - 1.0);
|
||||
if (fade_mode == 5)
|
||||
return 2.0 * p - 1.0;
|
||||
return 1.0 - 2.0 * p;
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
@@ -196,17 +197,19 @@ vec3 surface_gradient_color()
|
||||
direction_vec = vec2(1.0, 0.0);
|
||||
|
||||
float theta_deg = normalize_angle(degrees(atan(direction_vec.y, direction_vec.x)) - rotation_deg);
|
||||
float fade_factor = abs(offset_fade_factor(gradient_fade_mode, z_progress));
|
||||
float signed_fade_factor = offset_fade_factor(gradient_fade_mode, z_progress);
|
||||
float fade_factor = abs(signed_fade_factor);
|
||||
float sample_theta_deg = signed_fade_factor < 0.0 ? normalize_angle(theta_deg + 180.0) : theta_deg;
|
||||
float influences[MAX_GRADIENT_COMPONENTS];
|
||||
float edge_reaches[MAX_GRADIENT_COMPONENTS];
|
||||
float min_reach = 1000000.0;
|
||||
float max_reach = -1000000.0;
|
||||
float visibility_weights[MAX_GRADIENT_COMPONENTS];
|
||||
float min_visibility = 1.0;
|
||||
float max_visibility = 0.0;
|
||||
|
||||
for (int i = 0; i < MAX_GRADIENT_COMPONENTS; ++i) {
|
||||
influences[i] = 0.0;
|
||||
edge_reaches[i] = 0.0;
|
||||
visibility_weights[i] = 0.0;
|
||||
if (i < count)
|
||||
influences[i] = component_angular_influence(i, theta_deg);
|
||||
influences[i] = component_angular_influence(i, sample_theta_deg);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_GRADIENT_COMPONENTS; ++i) {
|
||||
@@ -223,24 +226,25 @@ vec3 surface_gradient_color()
|
||||
gradient_max_width_delta_limit_mm,
|
||||
gradient_minimum_offset_factors[i],
|
||||
gradient_strength_factors[i]);
|
||||
edge_reaches[i] = clamp(gradient_max_width_delta_limit_mm - width_delta_mm, 0.0, gradient_max_width_delta_limit_mm);
|
||||
min_reach = min(min_reach, edge_reaches[i]);
|
||||
max_reach = max(max_reach, edge_reaches[i]);
|
||||
visibility_weights[i] = 1.0 - clamp(width_delta_mm / max(gradient_max_width_delta_limit_mm, EPSILON), 0.0, 1.0);
|
||||
min_visibility = min(min_visibility, visibility_weights[i]);
|
||||
max_visibility = max(max_visibility, visibility_weights[i]);
|
||||
}
|
||||
|
||||
vec3 mixed_color = vec3(0.0);
|
||||
float total_weight = 0.0;
|
||||
float reach_span = max_reach - min_reach;
|
||||
vec3 target_color = vec3(0.0);
|
||||
float total_excess_weight = 0.0;
|
||||
for (int i = 0; i < MAX_GRADIENT_COMPONENTS; ++i) {
|
||||
if (i >= count)
|
||||
continue;
|
||||
float weight = reach_span > EPSILON ? clamp((edge_reaches[i] - min_reach) / reach_span, 0.0, 1.0) : 1.0;
|
||||
mixed_color += gradient_component_colors[i] * weight;
|
||||
total_weight += weight;
|
||||
float weight = max(0.0, visibility_weights[i] - min_visibility);
|
||||
target_color += gradient_component_colors[i] * weight;
|
||||
total_excess_weight += weight;
|
||||
}
|
||||
if (total_weight <= EPSILON)
|
||||
return gradient_component_colors[0];
|
||||
return clamp(mixed_color / total_weight, 0.0, 1.0);
|
||||
if (total_excess_weight <= EPSILON)
|
||||
return clamp(gradient_base_color, 0.0, 1.0);
|
||||
float contrast = clamp(max_visibility - min_visibility, 0.0, 1.0);
|
||||
target_color = clamp(target_color / total_excess_weight, 0.0, 1.0);
|
||||
return mix(clamp(gradient_base_color, 0.0, 1.0), target_color, contrast);
|
||||
}
|
||||
|
||||
float invalid_texture_mapping_checker()
|
||||
|
||||
@@ -18,6 +18,7 @@ uniform bool invalid_texture_mapping;
|
||||
uniform PrintVolumeDetection print_volume;
|
||||
|
||||
uniform int gradient_component_count;
|
||||
uniform vec3 gradient_base_color;
|
||||
uniform vec3 gradient_component_colors[MAX_GRADIENT_COMPONENTS];
|
||||
uniform float gradient_distances_mm[MAX_GRADIENT_COMPONENTS];
|
||||
uniform float gradient_angles_deg[MAX_GRADIENT_COMPONENTS];
|
||||
@@ -98,7 +99,7 @@ float offset_fade_factor(int fade_mode, float progress01)
|
||||
if (fade_mode == 4)
|
||||
return abs(2.0 * p - 1.0);
|
||||
if (fade_mode == 5)
|
||||
return 2.0 * p - 1.0;
|
||||
return 1.0 - 2.0 * p;
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
@@ -198,17 +199,19 @@ vec3 surface_gradient_color()
|
||||
direction_vec = vec2(1.0, 0.0);
|
||||
|
||||
float theta_deg = normalize_angle(degrees(atan(direction_vec.y, direction_vec.x)) - rotation_deg);
|
||||
float fade_factor = abs(offset_fade_factor(gradient_fade_mode, z_progress));
|
||||
float signed_fade_factor = offset_fade_factor(gradient_fade_mode, z_progress);
|
||||
float fade_factor = abs(signed_fade_factor);
|
||||
float sample_theta_deg = signed_fade_factor < 0.0 ? normalize_angle(theta_deg + 180.0) : theta_deg;
|
||||
float influences[MAX_GRADIENT_COMPONENTS];
|
||||
float edge_reaches[MAX_GRADIENT_COMPONENTS];
|
||||
float min_reach = 1000000.0;
|
||||
float max_reach = -1000000.0;
|
||||
float visibility_weights[MAX_GRADIENT_COMPONENTS];
|
||||
float min_visibility = 1.0;
|
||||
float max_visibility = 0.0;
|
||||
|
||||
for (int i = 0; i < MAX_GRADIENT_COMPONENTS; ++i) {
|
||||
influences[i] = 0.0;
|
||||
edge_reaches[i] = 0.0;
|
||||
visibility_weights[i] = 0.0;
|
||||
if (i < count)
|
||||
influences[i] = component_angular_influence(i, theta_deg);
|
||||
influences[i] = component_angular_influence(i, sample_theta_deg);
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_GRADIENT_COMPONENTS; ++i) {
|
||||
@@ -225,24 +228,25 @@ vec3 surface_gradient_color()
|
||||
gradient_max_width_delta_limit_mm,
|
||||
gradient_minimum_offset_factors[i],
|
||||
gradient_strength_factors[i]);
|
||||
edge_reaches[i] = clamp(gradient_max_width_delta_limit_mm - width_delta_mm, 0.0, gradient_max_width_delta_limit_mm);
|
||||
min_reach = min(min_reach, edge_reaches[i]);
|
||||
max_reach = max(max_reach, edge_reaches[i]);
|
||||
visibility_weights[i] = 1.0 - clamp(width_delta_mm / max(gradient_max_width_delta_limit_mm, EPSILON), 0.0, 1.0);
|
||||
min_visibility = min(min_visibility, visibility_weights[i]);
|
||||
max_visibility = max(max_visibility, visibility_weights[i]);
|
||||
}
|
||||
|
||||
vec3 mixed_color = vec3(0.0);
|
||||
float total_weight = 0.0;
|
||||
float reach_span = max_reach - min_reach;
|
||||
vec3 target_color = vec3(0.0);
|
||||
float total_excess_weight = 0.0;
|
||||
for (int i = 0; i < MAX_GRADIENT_COMPONENTS; ++i) {
|
||||
if (i >= count)
|
||||
continue;
|
||||
float weight = reach_span > EPSILON ? clamp((edge_reaches[i] - min_reach) / reach_span, 0.0, 1.0) : 1.0;
|
||||
mixed_color += gradient_component_colors[i] * weight;
|
||||
total_weight += weight;
|
||||
float weight = max(0.0, visibility_weights[i] - min_visibility);
|
||||
target_color += gradient_component_colors[i] * weight;
|
||||
total_excess_weight += weight;
|
||||
}
|
||||
if (total_weight <= EPSILON)
|
||||
return gradient_component_colors[0];
|
||||
return clamp(mixed_color / total_weight, 0.0, 1.0);
|
||||
if (total_excess_weight <= EPSILON)
|
||||
return clamp(gradient_base_color, 0.0, 1.0);
|
||||
float contrast = clamp(max_visibility - min_visibility, 0.0, 1.0);
|
||||
target_color = clamp(target_color / total_excess_weight, 0.0, 1.0);
|
||||
return mix(clamp(gradient_base_color, 0.0, 1.0), target_color, contrast);
|
||||
}
|
||||
|
||||
float invalid_texture_mapping_checker()
|
||||
|
||||
@@ -9800,12 +9800,15 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
|
||||
const float theta_deg =
|
||||
normalize_angle_deg_for_gcode(float(Geometry::rad2deg(std::atan2(theta_direction_y, theta_direction_x))));
|
||||
const float sample_theta_deg = state.signed_fade_factor < 0.f ?
|
||||
normalize_angle_deg_for_gcode(theta_deg + 180.f) :
|
||||
theta_deg;
|
||||
float raw_inset_mm = 0.f;
|
||||
for (size_t i = 0; i < component_ids.size(); ++i) {
|
||||
if (i == state.active_component_idx)
|
||||
continue;
|
||||
const float influence = component_angular_influence_for_gcode(component_ids[i],
|
||||
theta_deg,
|
||||
sample_theta_deg,
|
||||
component_ids,
|
||||
rotated_angles);
|
||||
raw_inset_mm += distances_mm[i] * influence;
|
||||
@@ -9839,7 +9842,7 @@ std::optional<PreferredSeamPoint> GCode::texture_mapping_seam_hiding_hint(const
|
||||
return std::nullopt;
|
||||
|
||||
const float centerline_shift_mm = base_centerline_shift_mm + 0.5f * width_delta_mm;
|
||||
const float centerline_outward_shift_mm = state.signed_fade_factor >= 0.f ? -centerline_shift_mm : centerline_shift_mm;
|
||||
const float centerline_outward_shift_mm = -centerline_shift_mm;
|
||||
const float outer_offset_mm = centerline_outward_shift_mm + 0.5f * target_width_mm;
|
||||
if (!std::isfinite(outer_offset_mm))
|
||||
return std::nullopt;
|
||||
@@ -10765,7 +10768,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
bool object_center_mode { false };
|
||||
Point object_center;
|
||||
float inset_strength_reference_mm { 0.f };
|
||||
float signed_fade_factor { 1.f };
|
||||
float max_width_delta_mm { 0.f };
|
||||
float base_outer_width_mm { 0.4f };
|
||||
float dither_pitch_mm { 0.08f };
|
||||
@@ -11002,7 +11004,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
outer_wall_gradient_dynamic_ctx.object_center_mode = object_center_mode;
|
||||
outer_wall_gradient_dynamic_ctx.object_center = object_center;
|
||||
outer_wall_gradient_dynamic_ctx.inset_strength_reference_mm = max_allowed_distance_mm;
|
||||
outer_wall_gradient_dynamic_ctx.signed_fade_factor = signed_fade_factor;
|
||||
outer_wall_gradient_dynamic_ctx.max_width_delta_mm = effective_max_width_delta_mm;
|
||||
outer_wall_gradient_dynamic_ctx.base_outer_width_mm = base_outer_width_mm;
|
||||
outer_wall_gradient_dynamic_ctx.dither_pitch_mm = offset_context->dither_pitch_mm;
|
||||
@@ -11027,7 +11028,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
if (std::abs(centerline_shift_mm) <= EPSILON)
|
||||
return true;
|
||||
|
||||
const bool reverse_shift = (signed_fade_factor < 0.f) != (centerline_shift_mm < 0.f);
|
||||
const bool reverse_shift = centerline_shift_mm < 0.f;
|
||||
const double shift_x = reverse_shift ? -mod.shift_unit_x : mod.shift_unit_x;
|
||||
const double shift_y = reverse_shift ? -mod.shift_unit_y : mod.shift_unit_y;
|
||||
const double shift_scaled = scale_(double(std::abs(centerline_shift_mm)));
|
||||
@@ -11805,8 +11806,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
if (std::abs(centerline_shift_mm) > EPSILON) {
|
||||
const double inward_x = -outward_x;
|
||||
const double inward_y = -outward_y;
|
||||
const bool reverse_shift =
|
||||
(outer_wall_gradient_dynamic_ctx.signed_fade_factor < 0.f) != (centerline_shift_mm < 0.f);
|
||||
const bool reverse_shift = centerline_shift_mm < 0.f;
|
||||
const double shift_x = reverse_shift ? -inward_x : inward_x;
|
||||
const double shift_y = reverse_shift ? -inward_y : inward_y;
|
||||
const double shift_scaled = scale_(double(std::abs(centerline_shift_mm)));
|
||||
|
||||
@@ -2512,7 +2512,7 @@ float texture_mapping_offset_fade_factor(int fade_mode, float progress01)
|
||||
case int(TextureMappingZone::OffsetFadeOutUp): return 1.f - p;
|
||||
case int(TextureMappingZone::OffsetFadeInOut): return 1.f - std::abs(2.f * p - 1.f);
|
||||
case int(TextureMappingZone::OffsetFadeOutIn): return std::abs(2.f * p - 1.f);
|
||||
case int(TextureMappingZone::OffsetFadeOutInReversed): return 2.f * p - 1.f;
|
||||
case int(TextureMappingZone::OffsetFadeOutInReversed): return 1.f - 2.f * p;
|
||||
default: return 1.f;
|
||||
}
|
||||
}
|
||||
@@ -2789,7 +2789,8 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
for (float &a : rotated_angles)
|
||||
a = normalize_texture_mapping_offset_angle_deg(a + rotation_deg);
|
||||
|
||||
const float fade_factor = std::abs(texture_mapping_offset_fade_factor(zone.offset_fade_mode, z_progress));
|
||||
const float signed_fade_factor = texture_mapping_offset_fade_factor(zone.offset_fade_mode, z_progress);
|
||||
const float fade_factor = std::abs(signed_fade_factor);
|
||||
if (fade_factor <= EPSILON)
|
||||
return std::nullopt;
|
||||
|
||||
@@ -2812,6 +2813,7 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
context.rotated_angles = std::move(rotated_angles);
|
||||
context.weight_field = std::move(weight_field);
|
||||
context.inset_strength_reference_mm = max_allowed_distance_mm;
|
||||
context.signed_fade_factor = signed_fade_factor;
|
||||
context.fade_factor = fade_factor;
|
||||
context.max_width_delta_mm = max_width_delta_limit_mm;
|
||||
context.dither_pitch_mm = dither_pitch_mm;
|
||||
@@ -2882,6 +2884,9 @@ float texture_mapping_offset_surface_inset_mm(const TextureMappingOffsetContext
|
||||
|
||||
const float theta_deg =
|
||||
normalize_texture_mapping_offset_angle_deg(float(Geometry::rad2deg(std::atan2(theta_direction_y, theta_direction_x))));
|
||||
const float sample_theta_deg = context.signed_fade_factor < 0.f ?
|
||||
normalize_texture_mapping_offset_angle_deg(theta_deg + 180.f) :
|
||||
theta_deg;
|
||||
float raw_inset_mm = 0.f;
|
||||
const size_t component_count = std::min(context.component_ids.size(), context.component_distances_mm.size());
|
||||
for (size_t i = 0; i < component_count; ++i) {
|
||||
@@ -2889,7 +2894,7 @@ float texture_mapping_offset_surface_inset_mm(const TextureMappingOffsetContext
|
||||
continue;
|
||||
const float influence =
|
||||
component_angular_influence(context.component_ids[i],
|
||||
theta_deg,
|
||||
sample_theta_deg,
|
||||
context.component_ids,
|
||||
context.rotated_angles);
|
||||
raw_inset_mm += context.component_distances_mm[i] * influence;
|
||||
|
||||
@@ -68,6 +68,7 @@ struct TextureMappingOffsetContext {
|
||||
std::vector<float> rotated_angles;
|
||||
TextureMappingOffsetWeightField weight_field;
|
||||
float inset_strength_reference_mm { 0.f };
|
||||
float signed_fade_factor { 1.f };
|
||||
float fade_factor { 1.f };
|
||||
float max_width_delta_mm { 0.f };
|
||||
float dither_pitch_mm { TextureMappingZone::DefaultDitheringResolutionMm };
|
||||
|
||||
@@ -99,6 +99,7 @@ struct SurfaceGradientPreviewSettings
|
||||
{
|
||||
std::vector<unsigned int> component_ids;
|
||||
std::vector<std::array<float, 3>> component_colors;
|
||||
std::array<float, 3> base_color { 0.f, 0.f, 0.f };
|
||||
std::vector<float> distances_mm;
|
||||
std::vector<float> angles_deg;
|
||||
std::vector<float> strength_factors;
|
||||
@@ -4145,17 +4146,16 @@ std::optional<SurfaceGradientPreviewSettings> surface_gradient_preview_settings_
|
||||
settings.strength_factors.emplace_back(std::clamp((std::isfinite(strength_pct) ? strength_pct : 100.f) / 100.f, 0.f, 1.f));
|
||||
settings.minimum_offset_factors.emplace_back(std::clamp((std::isfinite(minimum_offset_pct) ? minimum_offset_pct : 0.f) / 100.f, 0.f, 1.f));
|
||||
}
|
||||
const std::vector<float> base_weights(settings.component_colors.size(), 1.f);
|
||||
const ColorRGBA base_color = blend_component_colors(settings.component_colors, base_weights);
|
||||
settings.base_color = { base_color.r(), base_color.g(), base_color.b() };
|
||||
|
||||
const float max_distance_mm = TextureMappingManager::max_component_surface_offset_mm();
|
||||
settings.max_component_distance_mm = max_distance_mm;
|
||||
settings.distances_mm = TextureMappingManager::effective_offset_distances(zone, settings.component_ids.size());
|
||||
bool has_nonzero_distance = false;
|
||||
for (float &distance_mm : settings.distances_mm) {
|
||||
distance_mm = std::clamp(distance_mm, 0.f, max_distance_mm);
|
||||
has_nonzero_distance = has_nonzero_distance || distance_mm > k_epsilon;
|
||||
}
|
||||
if (!has_nonzero_distance)
|
||||
return std::nullopt;
|
||||
|
||||
settings.angles_deg = TextureMappingManager::effective_offset_angles(zone, settings.component_ids.size());
|
||||
settings.angle_mode = std::clamp(zone.offset_angle_mode,
|
||||
@@ -4177,8 +4177,9 @@ std::optional<SurfaceGradientPreviewSettings> surface_gradient_preview_settings_
|
||||
const float global_strength_factor =
|
||||
std::clamp(surface_gradient_preview_config_float("texture_mapping_outer_wall_gradient_global_strength", 100.f) / 100.f, 0.f, 1.f);
|
||||
settings.max_width_delta_limit_mm = std::min((base_outer_width_mm - min_outer_width_mm) * global_strength_factor, 2.f * max_distance_mm);
|
||||
if (!std::isfinite(settings.max_width_delta_limit_mm) || settings.max_width_delta_limit_mm <= k_epsilon)
|
||||
if (!std::isfinite(settings.max_width_delta_limit_mm))
|
||||
return std::nullopt;
|
||||
settings.max_width_delta_limit_mm = std::max(0.f, settings.max_width_delta_limit_mm);
|
||||
|
||||
const indexed_triangle_set &its = model_volume.mesh().its;
|
||||
if (its.vertices.empty())
|
||||
@@ -4325,6 +4326,7 @@ void set_surface_gradient_preview_uniforms(GLShaderProgram &shader, const Surfac
|
||||
const size_t count = settings == nullptr ? size_t(0) :
|
||||
std::min(settings->component_colors.size(), k_surface_gradient_preview_max_components);
|
||||
shader.set_uniform("gradient_component_count", int(count));
|
||||
shader.set_uniform("gradient_base_color", settings != nullptr ? settings->base_color : std::array<float, 3>{ 0.f, 0.f, 0.f });
|
||||
shader.set_uniform("gradient_max_component_distance_mm", settings != nullptr ? settings->max_component_distance_mm : 0.f);
|
||||
shader.set_uniform("gradient_max_width_delta_limit_mm", settings != nullptr ? settings->max_width_delta_limit_mm : 0.f);
|
||||
shader.set_uniform("gradient_angle_mode", settings != nullptr ? settings->angle_mode : int(TextureMappingZone::OffsetAngleObjectCenter));
|
||||
@@ -4840,6 +4842,17 @@ static bool texture_preview_zone_uses_halftone_model(const TextureMappingZone &z
|
||||
method == int(TextureMappingZone::DitheringHalftoneIncreasedDetail));
|
||||
}
|
||||
|
||||
static bool texture_preview_gradient_zone_uses_model(const TextureMappingZone &zone, size_t num_physical)
|
||||
{
|
||||
if (!zone.enabled || zone.deleted || !zone.is_2d_gradient())
|
||||
return false;
|
||||
if (TextureMappingManager::selected_component_ids(zone, num_physical).size() < 2)
|
||||
return true;
|
||||
|
||||
const std::vector<unsigned int> component_ids = decode_surface_gradient_component_ids(zone, num_physical);
|
||||
return component_ids.size() >= 2;
|
||||
}
|
||||
|
||||
static void texture_preview_mix_zone_baked_model_settings(size_t &signature,
|
||||
const TextureMappingZone &zone,
|
||||
size_t num_physical)
|
||||
@@ -4958,7 +4971,9 @@ size_t texture_preview_model_settings_signature(size_t num_physical,
|
||||
signature_mix(std::hash<int>{}(halftone_model ? 1 : 0));
|
||||
signature_mix(std::hash<int>{}(simulated_vertex_color_model ? 1 : 0));
|
||||
|
||||
if (gradient_zone || halftone_model || simulated_vertex_color_model)
|
||||
if (gradient_zone)
|
||||
signature_mix(std::hash<int>{}(texture_preview_gradient_zone_uses_model(zone, num_physical) ? 1 : 0));
|
||||
else if (halftone_model || simulated_vertex_color_model)
|
||||
texture_preview_mix_zone_baked_model_settings(signature, zone, num_physical);
|
||||
}
|
||||
return signature;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/iterator/counting_iterator.hpp>
|
||||
@@ -50,6 +51,7 @@
|
||||
#include <wx/simplebook.h>
|
||||
#include <wx/slider.h>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/timer.h>
|
||||
#ifdef _WIN32
|
||||
#include <wx/richtooltip.h>
|
||||
#include <wx/custombgwin.h>
|
||||
@@ -1092,9 +1094,12 @@ public:
|
||||
const TextureMappingZone &zone,
|
||||
size_t num_physical,
|
||||
const std::vector<double> &nozzle_diameters,
|
||||
const std::vector<wxColour> &palette)
|
||||
const std::vector<wxColour> &palette,
|
||||
std::function<void(const TextureMappingZone &)> live_preview = {})
|
||||
: wxDialog(parent, wxID_ANY, _L("Offset Gradient"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
, m_zone(zone)
|
||||
, m_live_preview(std::move(live_preview))
|
||||
, m_live_preview_timer(this)
|
||||
{
|
||||
const int gap = FromDIP(8);
|
||||
const int compact_gap = std::max(FromDIP(3), gap / 2);
|
||||
@@ -1133,7 +1138,7 @@ public:
|
||||
mode_row->Add(m_basic_angle_label, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, compact_gap);
|
||||
m_basic_angle_spin = new wxSpinCtrlDouble(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(84), -1),
|
||||
wxSP_ARROW_KEYS | wxALIGN_RIGHT | wxTE_PROCESS_ENTER, 0.0, 360.0,
|
||||
initial_angles.empty() ? 0.0 : std::clamp(double(initial_angles.front()), 0.0, 360.0), 1.0);
|
||||
initial_angles.empty() ? 0.0 : std::clamp(double(initial_angles.front()), 0.0, 360.0), 10.0);
|
||||
m_basic_angle_spin->SetDigits(1);
|
||||
mode_row->Add(m_basic_angle_spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, compact_gap);
|
||||
m_basic_angle_units = new wxStaticText(this, wxID_ANY, _L("deg"));
|
||||
@@ -1211,7 +1216,7 @@ public:
|
||||
row->Add(new wxStaticText(this, wxID_ANY, _L("%")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
wxSpinCtrlDouble *angle_spin = new wxSpinCtrlDouble(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(FromDIP(84), -1),
|
||||
wxSP_ARROW_KEYS | wxALIGN_RIGHT | wxTE_PROCESS_ENTER, 0.0, 360.0,
|
||||
i < initial_angles.size() ? std::clamp(double(initial_angles[i]), 0.0, 360.0) : 0.0, 1.0);
|
||||
i < initial_angles.size() ? std::clamp(double(initial_angles[i]), 0.0, 360.0) : 0.0, 10.0);
|
||||
angle_spin->SetDigits(1);
|
||||
row->Add(angle_spin, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, compact_gap);
|
||||
row->Add(new wxStaticText(this, wxID_ANY, _L("deg")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
@@ -1234,10 +1239,18 @@ public:
|
||||
EndModal(wxID_OK);
|
||||
});
|
||||
|
||||
m_mode_choice->Bind(wxEVT_CHOICE, [this](wxCommandEvent &) { update_advanced_visibility(); });
|
||||
m_mode_choice->Bind(wxEVT_CHOICE, [this](wxCommandEvent &) {
|
||||
update_advanced_visibility();
|
||||
emit_live_preview();
|
||||
});
|
||||
bind_live_preview_events();
|
||||
SetSizerAndFit(root);
|
||||
SetMinSize(wxSize(FromDIP(560), std::max(GetSize().GetHeight(), FromDIP(420))));
|
||||
update_advanced_visibility();
|
||||
if (m_live_preview) {
|
||||
Bind(wxEVT_TIMER, [this](wxTimerEvent &) { emit_live_preview(); });
|
||||
m_live_preview_timer.Start(100);
|
||||
}
|
||||
}
|
||||
|
||||
bool apply_to(TextureMappingZone &out)
|
||||
@@ -1303,7 +1316,67 @@ private:
|
||||
Fit();
|
||||
}
|
||||
|
||||
void bind_live_preview_events()
|
||||
{
|
||||
auto bind_spin = [this](wxSpinCtrlDouble *spin, double step, double min_value, double max_value) {
|
||||
if (spin == nullptr)
|
||||
return;
|
||||
spin->Bind(wxEVT_SPINCTRLDOUBLE, [this](wxSpinDoubleEvent &) { emit_live_preview(); });
|
||||
spin->Bind(wxEVT_TEXT, [this](wxCommandEvent &) { emit_live_preview(); });
|
||||
spin->Bind(wxEVT_TEXT_ENTER, [this](wxCommandEvent &) { emit_live_preview(); });
|
||||
spin->Bind(wxEVT_CHAR_HOOK, [this, spin, step, min_value, max_value](wxKeyEvent &evt) {
|
||||
const int key = evt.GetKeyCode();
|
||||
if (key != WXK_UP && key != WXK_NUMPAD_UP && key != WXK_DOWN && key != WXK_NUMPAD_DOWN) {
|
||||
evt.Skip();
|
||||
return;
|
||||
}
|
||||
const double direction = (key == WXK_UP || key == WXK_NUMPAD_UP) ? 1.0 : -1.0;
|
||||
spin->SetValue(std::clamp(spin->GetValue() + direction * step, min_value, max_value));
|
||||
emit_live_preview();
|
||||
});
|
||||
spin->Bind(wxEVT_KILL_FOCUS, [this](wxFocusEvent &evt) {
|
||||
emit_live_preview();
|
||||
evt.Skip();
|
||||
});
|
||||
};
|
||||
auto bind_check = [this](wxCheckBox *check) {
|
||||
if (check != nullptr)
|
||||
check->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) { emit_live_preview(); });
|
||||
};
|
||||
auto bind_choice = [this](wxChoice *choice) {
|
||||
if (choice != nullptr)
|
||||
choice->Bind(wxEVT_CHOICE, [this](wxCommandEvent &) { emit_live_preview(); });
|
||||
};
|
||||
|
||||
bind_spin(m_basic_distance_spin, 1.0, 0.0, 100.0);
|
||||
bind_spin(m_basic_angle_spin, 10.0, 0.0, 360.0);
|
||||
bind_spin(m_rotations_spin, 0.1, -64.0, 64.0);
|
||||
bind_spin(m_repeats_spin, 0.1, 1.0, 64.0);
|
||||
for (wxSpinCtrlDouble *spin : m_distance_spins)
|
||||
bind_spin(spin, 1.0, 0.0, 100.0);
|
||||
for (wxSpinCtrlDouble *spin : m_angle_spins)
|
||||
bind_spin(spin, 10.0, 0.0, 360.0);
|
||||
bind_check(m_rotation_enabled);
|
||||
bind_check(m_reverse_repeats);
|
||||
bind_check(m_clockwise);
|
||||
bind_choice(m_fade_choice);
|
||||
bind_choice(m_angle_mode_choice);
|
||||
}
|
||||
|
||||
void emit_live_preview()
|
||||
{
|
||||
if (!m_live_preview)
|
||||
return;
|
||||
TextureMappingZone preview;
|
||||
if (!apply_to(preview))
|
||||
return;
|
||||
preview.surface_pattern = int(TextureMappingZone::Gradient2D);
|
||||
m_live_preview(preview);
|
||||
}
|
||||
|
||||
TextureMappingZone m_zone;
|
||||
std::function<void(const TextureMappingZone &)> m_live_preview;
|
||||
wxTimer m_live_preview_timer;
|
||||
std::vector<unsigned int> m_component_ids;
|
||||
wxChoice *m_mode_choice {nullptr};
|
||||
wxSpinCtrlDouble *m_basic_distance_spin {nullptr};
|
||||
@@ -6316,7 +6389,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
gap);
|
||||
|
||||
auto *button_row = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto *offset_btn = new wxButton(editor, wxID_ANY, _L("Offset Gradient Settings"));
|
||||
auto *offset_btn = new wxButton(editor, wxID_ANY, _L("2D Gradient Settings"));
|
||||
auto *advanced_btn = new wxButton(editor, wxID_ANY, _L("Advanced Options"));
|
||||
button_row->Add(offset_btn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
button_row->Add(advanced_btn, 0, wxALIGN_CENTER_VERTICAL);
|
||||
@@ -6466,13 +6539,56 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
apply_controls();
|
||||
evt.Skip();
|
||||
});
|
||||
offset_btn->Bind(wxEVT_BUTTON, [this, zone_index, mgr_ptr, palette, nozzle_diameters, apply_zone](wxCommandEvent &) {
|
||||
offset_btn->Bind(wxEVT_BUTTON, [this,
|
||||
zone_index,
|
||||
mgr_ptr,
|
||||
palette,
|
||||
nozzle_diameters,
|
||||
apply_zone,
|
||||
set_config_string](wxCommandEvent &) {
|
||||
if (zone_index >= mgr_ptr->zones().size())
|
||||
return;
|
||||
TextureMappingZone updated = mgr_ptr->zones()[zone_index];
|
||||
TextureMappingOffsetGradientDialog dlg(this, updated, palette.size(), nozzle_diameters, palette);
|
||||
if (dlg.ShowModal() != wxID_OK || !dlg.apply_to(updated))
|
||||
const TextureMappingZone original = mgr_ptr->zones()[zone_index];
|
||||
const std::string original_serialized = mgr_ptr->serialize_entries();
|
||||
TextureMappingZone updated = original;
|
||||
bool live_preview_applied = false;
|
||||
auto redraw_live_preview = [this]() {
|
||||
if (p->plater == nullptr)
|
||||
return;
|
||||
auto mark_canvas_dirty = [](GLCanvas3D *canvas) {
|
||||
if (canvas == nullptr)
|
||||
return;
|
||||
canvas->set_as_dirty();
|
||||
canvas->request_extra_frame();
|
||||
if (wxGLCanvas *wx_canvas = canvas->get_wxglcanvas(); wx_canvas != nullptr && wx_canvas->IsShownOnScreen())
|
||||
canvas->render();
|
||||
};
|
||||
mark_canvas_dirty(p->plater->get_view3D_canvas3D());
|
||||
mark_canvas_dirty(p->plater->get_assmeble_canvas3D());
|
||||
};
|
||||
auto live_preview = [zone_index, mgr_ptr, &live_preview_applied, redraw_live_preview, set_config_string](const TextureMappingZone &preview) {
|
||||
if (zone_index >= mgr_ptr->zones().size())
|
||||
return;
|
||||
if (mgr_ptr->zones()[zone_index] == preview)
|
||||
return;
|
||||
mgr_ptr->zones()[zone_index] = preview;
|
||||
set_config_string("texture_mapping_definitions", mgr_ptr->serialize_entries());
|
||||
live_preview_applied = true;
|
||||
redraw_live_preview();
|
||||
};
|
||||
TextureMappingOffsetGradientDialog dlg(this, updated, palette.size(), nozzle_diameters, palette, live_preview);
|
||||
const int dialog_result = dlg.ShowModal();
|
||||
if (zone_index >= mgr_ptr->zones().size())
|
||||
return;
|
||||
if (live_preview_applied)
|
||||
mgr_ptr->zones()[zone_index] = original;
|
||||
if (live_preview_applied)
|
||||
set_config_string("texture_mapping_definitions", original_serialized);
|
||||
if (dialog_result != wxID_OK || !dlg.apply_to(updated)) {
|
||||
if (live_preview_applied)
|
||||
redraw_live_preview();
|
||||
return;
|
||||
}
|
||||
updated.surface_pattern = int(TextureMappingZone::Gradient2D);
|
||||
apply_zone(std::move(updated));
|
||||
CallAfter([this]() { update_texture_mapping_panel(false); });
|
||||
|
||||
Reference in New Issue
Block a user