Add blue noise, phase, angle and supersampling options for top-surface coloring

This commit is contained in:
sentientstardust
2026-05-26 11:14:25 +01:00
parent 15498a6942
commit c519c107e7
4 changed files with 487 additions and 78 deletions

View File

@@ -433,6 +433,10 @@ struct TopSurfaceImageRegionPlan {
bool contoning_replace_top_perimeters_with_infill = false;
bool contoning_recolor_surrounding_perimeters = false;
int contoning_perimeter_mode = TextureMappingZone::DefaultTopSurfaceContoningPerimeterMode;
bool contoning_layer_phase_enabled = false;
bool contoning_varied_infill_angles_enabled = false;
bool contoning_blue_noise_error_diffusion_enabled = false;
bool contoning_supersampled_cells_enabled = false;
};
enum class TopSurfaceImageSourceSurface {
@@ -670,6 +674,16 @@ struct TopSurfaceImageContoningVectorRegion {
int cell_count { 0 };
};
struct TopSurfaceImageContoningCellSample {
std::array<float, 3> rgb { { 0.f, 0.f, 0.f } };
int solve_layers { 0 };
};
struct TopSurfaceImageContoningSolvedLabel {
int label { -1 };
std::array<float, 3> rgb { { 0.f, 0.f, 0.f } };
};
static float top_surface_image_contoning_oklab_error(const std::array<float, 3> &lhs,
const std::array<float, 3> &rhs)
{
@@ -842,6 +856,68 @@ static float top_surface_image_contoning_sample_pitch_mm(const TopSurfaceImageRe
return std::clamp(pitch, 0.25f, std::max(0.25f, plan.contoning_min_feature_mm));
}
static float top_surface_image_contoning_angle_rad(int depth, bool varied_angles)
{
if (!varied_angles)
return (depth & 1) ? float(-PI / 4.0) : float(PI / 4.0);
switch ((depth % 4 + 4) % 4) {
case 0: return float(PI / 4.0);
case 1: return float(-PI / 4.0);
case 2: return 0.f;
default: return float(PI / 2.0);
}
}
static coord_t top_surface_image_contoning_grid_min(coord_t value, coord_t step, coord_t phase)
{
if (step <= 0)
return value;
const coord_t shifted = value - phase;
coord_t quotient = shifted / step;
if (shifted < 0 && shifted % step != 0)
--quotient;
return quotient * step + phase;
}
static std::pair<coord_t, coord_t> top_surface_image_contoning_grid_phase(coord_t step, int depth)
{
if (step <= 0)
return { 0, 0 };
static constexpr int phase_x[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
static constexpr int phase_y[8] = { 0, 4, 6, 2, 5, 1, 7, 3 };
const int idx = (depth % 8 + 8) % 8;
return {
coord_t((static_cast<long long>(step) * static_cast<long long>(phase_x[idx])) / 8),
coord_t((static_cast<long long>(step) * static_cast<long long>(phase_y[idx])) / 8)
};
}
static uint32_t top_surface_image_contoning_hash_u32(int col, int row, int depth, int channel)
{
uint32_t h = 2166136261u;
auto mix = [&h](uint32_t value) {
h ^= value;
h *= 16777619u;
};
mix(uint32_t(col) * 0x9e3779b9u);
mix(uint32_t(row) * 0x85ebca6bu);
mix(uint32_t(depth) * 0xc2b2ae35u);
mix(uint32_t(channel) * 0x27d4eb2fu);
h ^= h >> 16;
h *= 0x7feb352du;
h ^= h >> 15;
h *= 0x846ca68bu;
h ^= h >> 16;
return h;
}
static float top_surface_image_contoning_jitter(int col, int row, int depth, int channel)
{
const uint32_t h = top_surface_image_contoning_hash_u32(col, row, depth, channel);
const float unit = float(h & 0x00FFFFFFu) / float(0x00FFFFFFu);
return (unit - 0.5f) * 0.006f;
}
static bool top_surface_image_contoning_grid_component_printable(int cell_count,
int min_col,
int max_col,
@@ -1028,6 +1104,114 @@ static int top_surface_image_contoning_pattern_filaments(int stack_layers, int c
return std::max(1, std::min(clamped_stack_layers, clamped_pattern_filaments));
}
static std::optional<TopSurfaceImageContoningCellSample> top_surface_image_contoning_sample_cell(
const TextureMappingOffsetContext &context,
const ExPolygons &area,
const std::vector<ExPolygons> &source_stack_areas,
int stack_layers,
int pattern_filaments,
int depth,
coord_t x0,
coord_t y0,
coord_t x1,
coord_t y1,
float threshold_deg,
TopSurfaceImageSourceSurface source_surface,
bool supersampled)
{
TopSurfaceImageContoningCellSample out;
int sample_count = 0;
auto add_sample = [&](const Point &sample_point) {
if (!top_surface_image_expolygons_contain_point(area, sample_point))
return;
const int local_stack_layers =
top_surface_image_contoning_local_stack_layers_at_point(sample_point, source_stack_areas, stack_layers);
if (depth >= local_stack_layers)
return;
const int solve_layers = std::min({ local_stack_layers, stack_layers, pattern_filaments });
if (solve_layers <= 0)
return;
const float sample_x_mm = unscale<float>(sample_point.x());
const float sample_y_mm = unscale<float>(sample_point.y());
if (!top_surface_image_contoning_sample_eligible(context, sample_x_mm, sample_y_mm, threshold_deg, source_surface))
return;
const std::optional<std::array<float, 3>> rgb =
sample_weight_field_rgb(context.weight_field,
sample_x_mm,
sample_y_mm,
context.high_resolution_texture_sampling);
if (!rgb)
return;
out.rgb[0] += (*rgb)[0];
out.rgb[1] += (*rgb)[1];
out.rgb[2] += (*rgb)[2];
out.solve_layers = sample_count == 0 ? solve_layers : std::min(out.solve_layers, solve_layers);
++sample_count;
};
if (supersampled) {
static constexpr std::array<std::pair<double, double>, 5> offsets {
std::pair<double, double>{ 0.5, 0.5 },
std::pair<double, double>{ 0.25, 0.25 },
std::pair<double, double>{ 0.75, 0.25 },
std::pair<double, double>{ 0.25, 0.75 },
std::pair<double, double>{ 0.75, 0.75 }
};
for (const std::pair<double, double> &offset : offsets) {
const coord_t x = coord_t(std::llround(double(x0) + double(x1 - x0) * offset.first));
const coord_t y = coord_t(std::llround(double(y0) + double(y1 - y0) * offset.second));
add_sample(Point(x, y));
}
} else {
add_sample(Point((x0 + x1) / 2, (y0 + y1) / 2));
}
if (sample_count <= 0)
return std::nullopt;
out.rgb[0] = std::clamp(out.rgb[0] / float(sample_count), 0.f, 1.f);
out.rgb[1] = std::clamp(out.rgb[1] / float(sample_count), 0.f, 1.f);
out.rgb[2] = std::clamp(out.rgb[2] / float(sample_count), 0.f, 1.f);
if (out.solve_layers <= 0)
return std::nullopt;
return out;
}
static std::optional<TopSurfaceImageContoningSolvedLabel> top_surface_image_contoning_solve_label(
const std::array<float, 3> &rgb,
int solve_layers,
const TextureMappingContoningSolver &solver,
const PrintConfig &print_config,
std::vector<TopSurfaceImageContoningVectorLabel> &labels,
std::map<std::vector<unsigned int>, int> &label_by_stack)
{
TextureMappingContoningStack stack = solver.solve(rgb, solve_layers);
if (stack.bottom_to_top.empty())
return std::nullopt;
std::optional<std::array<float, 3>> stack_rgb =
top_surface_image_contoning_stack_rgb(stack.bottom_to_top, print_config);
if (!stack_rgb)
return std::nullopt;
top_surface_image_contoning_sort_stack_for_top_color(stack.bottom_to_top, *stack_rgb, print_config);
top_surface_image_contoning_spread_stack_repeats(stack.bottom_to_top);
auto label_it = label_by_stack.find(stack.bottom_to_top);
int label = -1;
if (label_it == label_by_stack.end()) {
TopSurfaceImageContoningVectorLabel label_data;
label_data.bottom_to_top = stack.bottom_to_top;
label_data.rgb = *stack_rgb;
label_data.oklab = color_solver_oklab_from_srgb(*stack_rgb);
label = int(labels.size());
labels.emplace_back(std::move(label_data));
label_by_stack.emplace(labels.back().bottom_to_top, label);
} else {
label = label_it->second;
}
TopSurfaceImageContoningSolvedLabel out;
out.label = label;
out.rgb = *stack_rgb;
return out;
}
static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_contoning_vector_regions(
const TopSurfaceImageRegionPlan &plan,
const Layer &source_layer,
@@ -1038,6 +1222,7 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
int depth,
const TextureMappingContoningSolver &solver,
TopSurfaceImageSourceSurface source_surface,
bool use_blue_noise_error_diffusion,
const ThrowIfCanceled *throw_if_canceled)
{
std::vector<TopSurfaceImageContoningVectorRegion> regions;
@@ -1069,8 +1254,14 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
const float pitch_mm = top_surface_image_contoning_sample_pitch_mm(plan, bbox);
const coord_t step = std::max<coord_t>(1, scale_(double(pitch_mm)));
const coord_t min_x = (bbox.min.x() / step) * step;
const coord_t min_y = (bbox.min.y() / step) * step;
const std::pair<coord_t, coord_t> grid_phase =
plan.contoning_layer_phase_enabled ? top_surface_image_contoning_grid_phase(step, depth) : std::pair<coord_t, coord_t>{ 0, 0 };
const coord_t min_x = plan.contoning_layer_phase_enabled ?
top_surface_image_contoning_grid_min(bbox.min.x(), step, grid_phase.first) :
(bbox.min.x() / step) * step;
const coord_t min_y = plan.contoning_layer_phase_enabled ?
top_surface_image_contoning_grid_min(bbox.min.y(), step, grid_phase.second) :
(bbox.min.y() / step) * step;
const int cols = std::max(0, int(std::ceil(double(bbox.max.x() - min_x) / double(step))));
const int rows = std::max(0, int(std::ceil(double(bbox.max.y() - min_y) / double(step))));
if (cols <= 0 || rows <= 0)
@@ -1091,60 +1282,102 @@ static std::vector<TopSurfaceImageContoningVectorRegion> top_surface_image_conto
const std::vector<ExPolygons> source_stack_areas =
top_surface_image_contoning_stack_areas(source_layer, plan.zone_id, stack_layers, source_surface, throw_if_canceled);
auto solve_cell = [&](int row, int col, const std::array<float, 3> &target_rgb, int solve_layers) {
std::optional<TopSurfaceImageContoningSolvedLabel> solved =
top_surface_image_contoning_solve_label(target_rgb, solve_layers, solver, print_config, labels, label_by_stack);
if (!solved)
return std::optional<TopSurfaceImageContoningSolvedLabel>();
grid[size_t(row * cols + col)] = solved->label;
return solved;
};
auto sample_cell = [&](int row, int col) {
const coord_t x0 = min_x + coord_t(col) * step;
const coord_t y0 = min_y + coord_t(row) * step;
const coord_t x1 = std::min<coord_t>(x0 + step, bbox.max.x());
const coord_t y1 = std::min<coord_t>(y0 + step, bbox.max.y());
if (x1 <= x0 || y1 <= y0)
return std::optional<TopSurfaceImageContoningCellSample>();
return top_surface_image_contoning_sample_cell(*context,
area,
source_stack_areas,
stack_layers,
pattern_filaments,
depth,
x0,
y0,
x1,
y1,
threshold_deg,
source_surface,
plan.contoning_supersampled_cells_enabled);
};
std::vector<std::optional<TopSurfaceImageContoningCellSample>> cell_samples(grid.size());
for (int row = 0; row < rows; ++row) {
if ((row & 15) == 0)
check_canceled(throw_if_canceled);
for (int col = 0; col < cols; ++col) {
const coord_t x0 = min_x + coord_t(col) * step;
const coord_t y0 = min_y + coord_t(row) * step;
const coord_t x1 = std::min<coord_t>(x0 + step, bbox.max.x());
const coord_t y1 = std::min<coord_t>(y0 + step, bbox.max.y());
if (x1 <= x0 || y1 <= y0)
continue;
const Point sample_point((x0 + x1) / 2, (y0 + y1) / 2);
if (!top_surface_image_expolygons_contain_point(area, sample_point))
continue;
const int local_stack_layers =
top_surface_image_contoning_local_stack_layers_at_point(sample_point, source_stack_areas, stack_layers);
if (depth >= local_stack_layers)
continue;
const int solve_layers = std::min({ local_stack_layers, stack_layers, pattern_filaments });
if (solve_layers <= 0)
continue;
const float sample_x_mm = unscale<float>(sample_point.x());
const float sample_y_mm = unscale<float>(sample_point.y());
if (!top_surface_image_contoning_sample_eligible(*context, sample_x_mm, sample_y_mm, threshold_deg, source_surface))
continue;
const std::optional<std::array<float, 3>> rgb =
sample_weight_field_rgb(context->weight_field,
sample_x_mm,
sample_y_mm,
context->high_resolution_texture_sampling);
if (!rgb)
continue;
TextureMappingContoningStack stack = solver.solve(*rgb, solve_layers);
if (stack.bottom_to_top.empty())
continue;
std::optional<std::array<float, 3>> stack_rgb =
top_surface_image_contoning_stack_rgb(stack.bottom_to_top, print_config);
if (!stack_rgb)
continue;
top_surface_image_contoning_sort_stack_for_top_color(stack.bottom_to_top, *stack_rgb, print_config);
top_surface_image_contoning_spread_stack_repeats(stack.bottom_to_top);
auto label_it = label_by_stack.find(stack.bottom_to_top);
int label = -1;
if (label_it == label_by_stack.end()) {
TopSurfaceImageContoningVectorLabel label_data;
label_data.bottom_to_top = stack.bottom_to_top;
label_data.rgb = *stack_rgb;
label_data.oklab = color_solver_oklab_from_srgb(*stack_rgb);
label = int(labels.size());
labels.emplace_back(std::move(label_data));
label_by_stack.emplace(labels.back().bottom_to_top, label);
} else {
label = label_it->second;
for (int col = 0; col < cols; ++col)
cell_samples[size_t(row * cols + col)] = sample_cell(row, col);
}
if (use_blue_noise_error_diffusion) {
std::vector<std::array<float, 3>> errors(grid.size(), std::array<float, 3>{ { 0.f, 0.f, 0.f } });
auto add_error = [&](int row, int col, const std::array<float, 3> &error, float factor) {
if (row < 0 || row >= rows || col < 0 || col >= cols)
return;
std::array<float, 3> &dst = errors[size_t(row * cols + col)];
dst[0] += error[0] * factor;
dst[1] += error[1] * factor;
dst[2] += error[2] * factor;
};
for (int row = 0; row < rows; ++row) {
if ((row & 15) == 0)
check_canceled(throw_if_canceled);
const bool left_to_right = (row & 1) == 0;
for (int step_col = 0; step_col < cols; ++step_col) {
const int col = left_to_right ? step_col : cols - 1 - step_col;
const std::optional<TopSurfaceImageContoningCellSample> &sample = cell_samples[size_t(row * cols + col)];
if (!sample)
continue;
const size_t grid_idx = size_t(row * cols + col);
std::array<float, 3> target_rgb {
std::clamp(sample->rgb[0] + errors[grid_idx][0] + top_surface_image_contoning_jitter(col, row, depth, 0), 0.f, 1.f),
std::clamp(sample->rgb[1] + errors[grid_idx][1] + top_surface_image_contoning_jitter(col, row, depth, 1), 0.f, 1.f),
std::clamp(sample->rgb[2] + errors[grid_idx][2] + top_surface_image_contoning_jitter(col, row, depth, 2), 0.f, 1.f)
};
const std::optional<TopSurfaceImageContoningSolvedLabel> solved =
solve_cell(row, col, target_rgb, sample->solve_layers);
if (!solved)
continue;
const std::array<float, 3> error {
target_rgb[0] - solved->rgb[0],
target_rgb[1] - solved->rgb[1],
target_rgb[2] - solved->rgb[2]
};
if (left_to_right) {
add_error(row, col + 1, error, 7.f / 16.f);
add_error(row + 1, col - 1, error, 3.f / 16.f);
add_error(row + 1, col, error, 5.f / 16.f);
add_error(row + 1, col + 1, error, 1.f / 16.f);
} else {
add_error(row, col - 1, error, 7.f / 16.f);
add_error(row + 1, col + 1, error, 3.f / 16.f);
add_error(row + 1, col, error, 5.f / 16.f);
add_error(row + 1, col - 1, error, 1.f / 16.f);
}
}
}
} else {
for (int row = 0; row < rows; ++row) {
if ((row & 15) == 0)
check_canceled(throw_if_canceled);
for (int col = 0; col < cols; ++col) {
const std::optional<TopSurfaceImageContoningCellSample> &sample = cell_samples[size_t(row * cols + col)];
if (!sample)
continue;
solve_cell(row, col, sample->rgb, sample->solve_layers);
}
grid[size_t(row * cols + col)] = label;
}
}
@@ -1233,32 +1466,71 @@ static void top_surface_image_append_contoning_slices(TopSurfaceImageRegionPlan
std::vector<ExPolygons> by_component(print_config.filament_colour.values.size() + 1);
std::vector<ExPolygons> perimeter_by_component(print_config.filament_colour.values.size() + 1);
const std::vector<TopSurfaceImageContoningVectorRegion> stack_regions =
top_surface_image_contoning_vector_regions(plan,
source_layer,
perimeter_area,
object,
zone,
print_config,
depth,
solver,
source_surface,
throw_if_canceled);
for (const TopSurfaceImageContoningVectorRegion &region : stack_regions) {
check_canceled(throw_if_canceled);
if (depth < 0 || region.bottom_to_top.empty() || region.area.empty())
continue;
const int pattern_depth = depth % int(region.bottom_to_top.size());
const unsigned int component_id =
region.bottom_to_top[size_t(int(region.bottom_to_top.size()) - 1 - pattern_depth)];
if (component_id == 0 || component_id >= by_component.size())
continue;
append(perimeter_by_component[component_id], region.area);
if (!area.empty()) {
ExPolygons component_area = intersection_ex(region.area, area, ApplySafetyOffset::Yes);
if (!component_area.empty())
append(by_component[component_id], std::move(component_area));
auto append_regions = [&](const std::vector<TopSurfaceImageContoningVectorRegion> &regions,
bool for_fill,
bool for_perimeter) {
for (const TopSurfaceImageContoningVectorRegion &region : regions) {
check_canceled(throw_if_canceled);
if (depth < 0 || region.bottom_to_top.empty() || region.area.empty())
continue;
const int pattern_depth = depth % int(region.bottom_to_top.size());
const unsigned int component_id =
region.bottom_to_top[size_t(int(region.bottom_to_top.size()) - 1 - pattern_depth)];
if (component_id == 0 || component_id >= by_component.size())
continue;
if (for_perimeter)
append(perimeter_by_component[component_id], region.area);
if (for_fill && !area.empty()) {
ExPolygons component_area = intersection_ex(region.area, area, ApplySafetyOffset::Yes);
if (!component_area.empty())
append(by_component[component_id], std::move(component_area));
}
}
};
if (plan.contoning_blue_noise_error_diffusion_enabled) {
if (!area.empty()) {
const std::vector<TopSurfaceImageContoningVectorRegion> fill_regions =
top_surface_image_contoning_vector_regions(plan,
source_layer,
area,
object,
zone,
print_config,
depth,
solver,
source_surface,
true,
throw_if_canceled);
append_regions(fill_regions, true, false);
}
const std::vector<TopSurfaceImageContoningVectorRegion> perimeter_regions =
top_surface_image_contoning_vector_regions(plan,
source_layer,
perimeter_area,
object,
zone,
print_config,
depth,
solver,
source_surface,
false,
throw_if_canceled);
append_regions(perimeter_regions, false, true);
} else {
const std::vector<TopSurfaceImageContoningVectorRegion> stack_regions =
top_surface_image_contoning_vector_regions(plan,
source_layer,
perimeter_area,
object,
zone,
print_config,
depth,
solver,
source_surface,
false,
throw_if_canceled);
append_regions(stack_regions, true, true);
}
ExPolygons depth_taken;
@@ -1287,7 +1559,7 @@ static void top_surface_image_append_contoning_slices(TopSurfaceImageRegionPlan
slice.component_count = size_t(pattern_filaments);
slice.contoning = true;
slice.lower_surface = source_surface == TopSurfaceImageSourceSurface::Bottom;
slice.angle_rad = (depth & 1) ? float(-PI / 4.0) : float(PI / 4.0);
slice.angle_rad = top_surface_image_contoning_angle_rad(depth, plan.contoning_varied_infill_angles_enabled);
slice.area = std::move(component_area);
slice.perimeter_area = std::move(component_perimeter_area);
plan.slices.emplace_back(std::move(slice));
@@ -1382,6 +1654,10 @@ static std::vector<TopSurfaceImageRegionPlan> top_surface_image_region_plans(con
std::clamp(zone->top_surface_contoning_perimeter_mode,
int(TextureMappingZone::ContoningPerimeterSegmentBlocks),
int(TextureMappingZone::ContoningPerimeterSegmentInfill));
plan.contoning_layer_phase_enabled = zone->top_surface_contoning_layer_phase_enabled;
plan.contoning_varied_infill_angles_enabled = zone->top_surface_contoning_varied_infill_angles_enabled;
plan.contoning_blue_noise_error_diffusion_enabled = zone->top_surface_contoning_blue_noise_error_diffusion_enabled;
plan.contoning_supersampled_cells_enabled = zone->top_surface_contoning_supersampled_cells_enabled;
const TextureMappingContoningSolver contoning_solver(*zone, print_config, components);
const int stack_depth = plan.contoning ?
@@ -3111,8 +3387,11 @@ std::vector<SurfaceFill> group_fills(const Layer &layer,
params.flow = layerm.flow(frSolidInfill);
params.spacing = params.flow.spacing();
surface_fills.emplace_back(params);
surface_fills.back().region_id = region_id;
surface_fills.back().surface.surface_type = stInternalSolid;
surface_fills.back().surface.thickness = layer.height;
surface_fills.back().region_id_group.push_back(region_id);
surface_fills.back().no_overlap_expolygons = layerm.fill_no_overlap_expolygons;
surface_fills.back().expolygons = std::move(extensions);
} else {
append(extensions, std::move(internal_solid_fill->expolygons));
@@ -3216,6 +3495,10 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree,
for (SurfaceFill &surface_fill : surface_fills) {
check_canceled(throw_if_canceled_ptr);
if (surface_fill.expolygons.empty() ||
surface_fill.region_id >= this->m_regions.size() ||
this->m_regions[surface_fill.region_id] == nullptr)
continue;
// Create the filler object.
std::unique_ptr<Fill> f = std::unique_ptr<Fill>(Fill::new_from_type(surface_fill.params.pattern));
f->set_bounding_box(bbox);

View File

@@ -1057,6 +1057,10 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
top_surface_contoning_replace_top_perimeters_with_infill == rhs.top_surface_contoning_replace_top_perimeters_with_infill &&
top_surface_contoning_recolor_surrounding_perimeters == rhs.top_surface_contoning_recolor_surrounding_perimeters &&
top_surface_contoning_perimeter_mode == rhs.top_surface_contoning_perimeter_mode &&
top_surface_contoning_layer_phase_enabled == rhs.top_surface_contoning_layer_phase_enabled &&
top_surface_contoning_varied_infill_angles_enabled == rhs.top_surface_contoning_varied_infill_angles_enabled &&
top_surface_contoning_blue_noise_error_diffusion_enabled == rhs.top_surface_contoning_blue_noise_error_diffusion_enabled &&
top_surface_contoning_supersampled_cells_enabled == rhs.top_surface_contoning_supersampled_cells_enabled &&
compact_offset_mode == rhs.compact_offset_mode &&
use_legacy_fixed_color_mode == rhs.use_legacy_fixed_color_mode &&
high_speed_image_texture_sampling == rhs.high_speed_image_texture_sampling &&
@@ -1443,6 +1447,13 @@ std::string TextureMappingManager::serialize_entries()
clamp_int(zone.top_surface_contoning_perimeter_mode,
int(TextureMappingZone::ContoningPerimeterSegmentBlocks),
int(TextureMappingZone::ContoningPerimeterSegmentInfill));
texture["top_surface_contoning_layer_phase_enabled"] = zone.top_surface_contoning_layer_phase_enabled;
texture["top_surface_contoning_varied_infill_angles_enabled"] =
zone.top_surface_contoning_varied_infill_angles_enabled;
texture["top_surface_contoning_blue_noise_error_diffusion_enabled"] =
zone.top_surface_contoning_blue_noise_error_diffusion_enabled;
texture["top_surface_contoning_supersampled_cells_enabled"] =
zone.top_surface_contoning_supersampled_cells_enabled;
texture["compact_offset_mode"] = zone.compact_offset_mode;
texture["use_legacy_fixed_color_mode"] = zone.use_legacy_fixed_color_mode;
texture["high_speed_image_texture_sampling"] = true;
@@ -1709,6 +1720,18 @@ void TextureMappingManager::load_entries(const std::string &serialized,
int(TextureMappingZone::ContoningPerimeterSegmentInfill));
if (zone.top_surface_contoning_replace_top_perimeters_with_infill)
zone.top_surface_contoning_recolor_surrounding_perimeters = false;
zone.top_surface_contoning_layer_phase_enabled =
texture.value("top_surface_contoning_layer_phase_enabled",
TextureMappingZone::DefaultTopSurfaceContoningLayerPhaseEnabled);
zone.top_surface_contoning_varied_infill_angles_enabled =
texture.value("top_surface_contoning_varied_infill_angles_enabled",
TextureMappingZone::DefaultTopSurfaceContoningVariedInfillAnglesEnabled);
zone.top_surface_contoning_blue_noise_error_diffusion_enabled =
texture.value("top_surface_contoning_blue_noise_error_diffusion_enabled",
TextureMappingZone::DefaultTopSurfaceContoningBlueNoiseErrorDiffusionEnabled);
zone.top_surface_contoning_supersampled_cells_enabled =
texture.value("top_surface_contoning_supersampled_cells_enabled",
TextureMappingZone::DefaultTopSurfaceContoningSupersampledCellsEnabled);
zone.compact_offset_mode = texture.value("compact_offset_mode", TextureMappingZone::DefaultCompactOffsetMode);
zone.use_legacy_fixed_color_mode =
texture.value("use_legacy_fixed_color_mode", TextureMappingZone::DefaultUseLegacyFixedColorMode);

View File

@@ -179,6 +179,10 @@ struct TextureMappingZone
static constexpr bool DefaultTopSurfaceContoningReplaceTopPerimetersWithInfill = false;
static constexpr bool DefaultTopSurfaceContoningRecolorSurroundingPerimeters = false;
static constexpr int DefaultTopSurfaceContoningPerimeterMode = int(ContoningPerimeterDividedLine);
static constexpr bool DefaultTopSurfaceContoningLayerPhaseEnabled = false;
static constexpr bool DefaultTopSurfaceContoningVariedInfillAnglesEnabled = false;
static constexpr bool DefaultTopSurfaceContoningBlueNoiseErrorDiffusionEnabled = false;
static constexpr bool DefaultTopSurfaceContoningSupersampledCellsEnabled = false;
static constexpr bool DefaultCompactOffsetMode = true;
static constexpr bool DefaultUseLegacyFixedColorMode = false;
static constexpr bool DefaultHighSpeedImageTextureSampling = true;
@@ -282,6 +286,10 @@ struct TextureMappingZone
bool top_surface_contoning_replace_top_perimeters_with_infill = DefaultTopSurfaceContoningReplaceTopPerimetersWithInfill;
bool top_surface_contoning_recolor_surrounding_perimeters = DefaultTopSurfaceContoningRecolorSurroundingPerimeters;
int top_surface_contoning_perimeter_mode = DefaultTopSurfaceContoningPerimeterMode;
bool top_surface_contoning_layer_phase_enabled = DefaultTopSurfaceContoningLayerPhaseEnabled;
bool top_surface_contoning_varied_infill_angles_enabled = DefaultTopSurfaceContoningVariedInfillAnglesEnabled;
bool top_surface_contoning_blue_noise_error_diffusion_enabled = DefaultTopSurfaceContoningBlueNoiseErrorDiffusionEnabled;
bool top_surface_contoning_supersampled_cells_enabled = DefaultTopSurfaceContoningSupersampledCellsEnabled;
bool compact_offset_mode = DefaultCompactOffsetMode;
bool use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
bool high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;
@@ -401,6 +409,10 @@ struct TextureMappingZone
top_surface_contoning_replace_top_perimeters_with_infill = DefaultTopSurfaceContoningReplaceTopPerimetersWithInfill;
top_surface_contoning_recolor_surrounding_perimeters = DefaultTopSurfaceContoningRecolorSurroundingPerimeters;
top_surface_contoning_perimeter_mode = DefaultTopSurfaceContoningPerimeterMode;
top_surface_contoning_layer_phase_enabled = DefaultTopSurfaceContoningLayerPhaseEnabled;
top_surface_contoning_varied_infill_angles_enabled = DefaultTopSurfaceContoningVariedInfillAnglesEnabled;
top_surface_contoning_blue_noise_error_diffusion_enabled = DefaultTopSurfaceContoningBlueNoiseErrorDiffusionEnabled;
top_surface_contoning_supersampled_cells_enabled = DefaultTopSurfaceContoningSupersampledCellsEnabled;
compact_offset_mode = DefaultCompactOffsetMode;
use_legacy_fixed_color_mode = DefaultUseLegacyFixedColorMode;
high_speed_image_texture_sampling = DefaultHighSpeedImageTextureSampling;

View File

@@ -1908,6 +1908,10 @@ public:
bool top_surface_contoning_replace_top_perimeters_with_infill,
bool top_surface_contoning_recolor_surrounding_perimeters,
int top_surface_contoning_perimeter_mode,
bool top_surface_contoning_layer_phase_enabled,
bool top_surface_contoning_varied_infill_angles_enabled,
bool top_surface_contoning_blue_noise_error_diffusion_enabled,
bool top_surface_contoning_supersampled_cells_enabled,
const TextureMappingManager &texture_mapping_zones,
const TextureMappingGlobalSettings &global_settings,
const TextureMappingPrimeTowerImage &prime_tower_image,
@@ -2594,6 +2598,42 @@ public:
0,
wxEXPAND | wxTOP | wxBOTTOM,
gap / 2);
m_top_surface_contoning_layer_phase_checkbox =
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Layer phase detail"));
m_top_surface_contoning_layer_phase_checkbox->SetValue(top_surface_contoning_layer_phase_enabled);
m_top_surface_contoning_layer_phase_checkbox->SetMinSize(
wxSize(-1, std::max(m_top_surface_contoning_layer_phase_checkbox->GetBestSize().GetHeight(), FromDIP(24))));
contoning_checkboxes_root->Add(m_top_surface_contoning_layer_phase_checkbox,
0,
wxEXPAND | wxTOP | wxBOTTOM,
gap / 2);
m_top_surface_contoning_varied_infill_angles_checkbox =
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Varied infill angles"));
m_top_surface_contoning_varied_infill_angles_checkbox->SetValue(top_surface_contoning_varied_infill_angles_enabled);
m_top_surface_contoning_varied_infill_angles_checkbox->SetMinSize(
wxSize(-1, std::max(m_top_surface_contoning_varied_infill_angles_checkbox->GetBestSize().GetHeight(), FromDIP(24))));
contoning_checkboxes_root->Add(m_top_surface_contoning_varied_infill_angles_checkbox,
0,
wxEXPAND | wxTOP | wxBOTTOM,
gap / 2);
m_top_surface_contoning_blue_noise_error_diffusion_checkbox =
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Blue-noise error diffusion"));
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->SetValue(top_surface_contoning_blue_noise_error_diffusion_enabled);
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->SetMinSize(
wxSize(-1, std::max(m_top_surface_contoning_blue_noise_error_diffusion_checkbox->GetBestSize().GetHeight(), FromDIP(24))));
contoning_checkboxes_root->Add(m_top_surface_contoning_blue_noise_error_diffusion_checkbox,
0,
wxEXPAND | wxTOP | wxBOTTOM,
gap / 2);
m_top_surface_contoning_supersampled_cells_checkbox =
new wxCheckBox(m_top_surface_contoning_checkboxes_panel, wxID_ANY, _L("Supersampled cell colors"));
m_top_surface_contoning_supersampled_cells_checkbox->SetValue(top_surface_contoning_supersampled_cells_enabled);
m_top_surface_contoning_supersampled_cells_checkbox->SetMinSize(
wxSize(-1, std::max(m_top_surface_contoning_supersampled_cells_checkbox->GetBestSize().GetHeight(), FromDIP(24))));
contoning_checkboxes_root->Add(m_top_surface_contoning_supersampled_cells_checkbox,
0,
wxEXPAND | wxTOP | wxBOTTOM,
gap / 2);
top_surface_box->Add(m_top_surface_contoning_checkboxes_panel, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, gap);
m_top_surface_contoning_only_color_surface_infill_checkbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &) {
update_top_surface_image_options_visibility(true);
@@ -2986,6 +3026,26 @@ public:
int(TextureMappingZone::ContoningPerimeterSegmentInfill)) :
TextureMappingZone::DefaultTopSurfaceContoningPerimeterMode;
}
bool top_surface_contoning_layer_phase_enabled() const
{
return m_top_surface_contoning_layer_phase_checkbox != nullptr &&
m_top_surface_contoning_layer_phase_checkbox->GetValue();
}
bool top_surface_contoning_varied_infill_angles_enabled() const
{
return m_top_surface_contoning_varied_infill_angles_checkbox != nullptr &&
m_top_surface_contoning_varied_infill_angles_checkbox->GetValue();
}
bool top_surface_contoning_blue_noise_error_diffusion_enabled() const
{
return m_top_surface_contoning_blue_noise_error_diffusion_checkbox != nullptr &&
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->GetValue();
}
bool top_surface_contoning_supersampled_cells_enabled() const
{
return m_top_surface_contoning_supersampled_cells_checkbox != nullptr &&
m_top_surface_contoning_supersampled_cells_checkbox->GetValue();
}
bool minimum_visibility_offset_enabled() const
{
return m_minimum_visibility_offset_checkbox && m_minimum_visibility_offset_checkbox->GetValue();
@@ -3457,6 +3517,22 @@ private:
m_top_surface_contoning_perimeter_mode_panel->Show(show_perimeter_mode);
if (m_top_surface_contoning_perimeter_mode_choice != nullptr)
m_top_surface_contoning_perimeter_mode_choice->Enable(show_perimeter_mode);
if (m_top_surface_contoning_layer_phase_checkbox != nullptr) {
m_top_surface_contoning_layer_phase_checkbox->Show(contoning);
m_top_surface_contoning_layer_phase_checkbox->Enable(contoning);
}
if (m_top_surface_contoning_varied_infill_angles_checkbox != nullptr) {
m_top_surface_contoning_varied_infill_angles_checkbox->Show(contoning);
m_top_surface_contoning_varied_infill_angles_checkbox->Enable(contoning);
}
if (m_top_surface_contoning_blue_noise_error_diffusion_checkbox != nullptr) {
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->Show(contoning);
m_top_surface_contoning_blue_noise_error_diffusion_checkbox->Enable(contoning);
}
if (m_top_surface_contoning_supersampled_cells_checkbox != nullptr) {
m_top_surface_contoning_supersampled_cells_checkbox->Show(contoning);
m_top_surface_contoning_supersampled_cells_checkbox->Enable(contoning);
}
if (m_top_surface_image_fixed_coloring_filaments_checkbox != nullptr) {
m_top_surface_image_fixed_coloring_filaments_checkbox->Show(!contoning_selected);
m_top_surface_image_fixed_coloring_filaments_checkbox->Enable(enabled && !contoning_selected);
@@ -3523,6 +3599,10 @@ private:
wxCheckBox *m_top_surface_contoning_recolor_surrounding_perimeters_checkbox {nullptr};
wxPanel *m_top_surface_contoning_perimeter_mode_panel {nullptr};
wxChoice *m_top_surface_contoning_perimeter_mode_choice {nullptr};
wxCheckBox *m_top_surface_contoning_layer_phase_checkbox {nullptr};
wxCheckBox *m_top_surface_contoning_varied_infill_angles_checkbox {nullptr};
wxCheckBox *m_top_surface_contoning_blue_noise_error_diffusion_checkbox {nullptr};
wxCheckBox *m_top_surface_contoning_supersampled_cells_checkbox {nullptr};
wxCheckBox *m_use_legacy_fixed_color_mode_checkbox {nullptr};
wxCheckBox *m_minimum_visibility_offset_checkbox {nullptr};
wxSpinCtrl *m_minimum_visibility_offset_spin {nullptr};
@@ -8527,6 +8607,10 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
updated.top_surface_contoning_replace_top_perimeters_with_infill,
updated.top_surface_contoning_recolor_surrounding_perimeters,
updated.top_surface_contoning_perimeter_mode,
updated.top_surface_contoning_layer_phase_enabled,
updated.top_surface_contoning_varied_infill_angles_enabled,
updated.top_surface_contoning_blue_noise_error_diffusion_enabled,
updated.top_surface_contoning_supersampled_cells_enabled,
bundle->texture_mapping_zones,
bundle->texture_mapping_global_settings,
wxGetApp().model().texture_mapping_prime_tower_image,
@@ -8587,6 +8671,13 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
updated.top_surface_contoning_recolor_surrounding_perimeters =
dlg.top_surface_contoning_recolor_surrounding_perimeters();
updated.top_surface_contoning_perimeter_mode = dlg.top_surface_contoning_perimeter_mode();
updated.top_surface_contoning_layer_phase_enabled = dlg.top_surface_contoning_layer_phase_enabled();
updated.top_surface_contoning_varied_infill_angles_enabled =
dlg.top_surface_contoning_varied_infill_angles_enabled();
updated.top_surface_contoning_blue_noise_error_diffusion_enabled =
dlg.top_surface_contoning_blue_noise_error_diffusion_enabled();
updated.top_surface_contoning_supersampled_cells_enabled =
dlg.top_surface_contoning_supersampled_cells_enabled();
if (updated.top_surface_image_printing_enabled &&
updated.top_surface_image_printing_method == int(TextureMappingZone::TopSurfaceImageContoning)) {
updated.modulation_mode = int(TextureMappingZone::ModulationPerimeterPathV2);