mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 13:32:44 +00:00
clean up comments
This commit is contained in:
@@ -38,8 +38,8 @@ extern bool load_obj(const char *path, TriangleMesh *mesh, ObjInfo &vertex_color
|
|||||||
extern bool load_obj(const char *path, Model *model, ObjInfo &vertex_colors, std::string &message, const char *object_name = nullptr, ObjParser::MtlData *out_mtl = nullptr);
|
extern bool load_obj(const char *path, Model *model, ObjInfo &vertex_colors, std::string &message, const char *object_name = nullptr, ObjParser::MtlData *out_mtl = nullptr);
|
||||||
|
|
||||||
struct TexturedMesh;
|
struct TexturedMesh;
|
||||||
// Build a TexturedMesh (vertices + per-face UVs + decoded texture images) from a parsed OBJ
|
// Build a TexturedMesh (vertices + per-face UVs + the texture files named by map_Kd) from a
|
||||||
// plus its material table, so the texture-to-color importer can sample face colours.
|
// parsed OBJ plus its material table, so the texture-to-color importer can sample face colours.
|
||||||
extern bool obj_to_textured_mesh(
|
extern bool obj_to_textured_mesh(
|
||||||
const ObjInfo& obj_info,
|
const ObjInfo& obj_info,
|
||||||
const indexed_triangle_set& its,
|
const indexed_triangle_set& its,
|
||||||
|
|||||||
@@ -6106,8 +6106,7 @@ LayerResult GCode::process_layer(
|
|||||||
// A mixed-color slot is absent from layer_tools.extruders by design: resolve_mixed_filaments()
|
// A mixed-color slot is absent from layer_tools.extruders by design: resolve_mixed_filaments()
|
||||||
// replaced it with its physical components. Its geometry is still keyed under the slot in
|
// replaced it with its physical components. Its geometry is still keyed under the slot in
|
||||||
// by_extruder though, and the sublayer emitter looks the plan up by slot id, so append the
|
// by_extruder though, and the sublayer emitter looks the plan up by slot id, so append the
|
||||||
// slots here. Appended (not merged) so the existing order is untouched, and empty for every
|
// slots here. Appending rather than merging leaves the flush-optimized order untouched.
|
||||||
// configuration without sublayer splitting.
|
|
||||||
std::vector<unsigned int> plan_filaments = layer_tools.extruders;
|
std::vector<unsigned int> plan_filaments = layer_tools.extruders;
|
||||||
for (const auto &grp : layer_tools.mixed_sub_layer_groups)
|
for (const auto &grp : layer_tools.mixed_sub_layer_groups)
|
||||||
if (std::find(plan_filaments.begin(), plan_filaments.end(), grp.mixed_slot_0based) == plan_filaments.end())
|
if (std::find(plan_filaments.begin(), plan_filaments.end(), grp.mixed_slot_0based) == plan_filaments.end())
|
||||||
@@ -6593,8 +6592,8 @@ LayerResult GCode::process_layer(
|
|||||||
|
|
||||||
// Mixed-color sublayer extrusion: if this extruder is a component of a mixed sublayer
|
// Mixed-color sublayer extrusion: if this extruder is a component of a mixed sublayer
|
||||||
// group, extrude the mixed slot's geometry at the appropriate sub-Z with scaled flow.
|
// group, extrude the mixed slot's geometry at the appropriate sub-Z with scaled flow.
|
||||||
// Ported from BambuStudio's 混色耗材 feature; adapted to Orca's InstanceVisit-based
|
// Ported from BambuStudio and adapted to Orca's instance loop and its finer-grained
|
||||||
// instance loop and its finer-grained per-role region filament options.
|
// per-role region filament options.
|
||||||
for (const auto &grp : layer_tools.mixed_sub_layer_groups) {
|
for (const auto &grp : layer_tools.mixed_sub_layer_groups) {
|
||||||
int sub_idx = -1;
|
int sub_idx = -1;
|
||||||
for (size_t k = 0; k < grp.components_0based.size(); ++k) {
|
for (size_t k = 0; k < grp.components_0based.size(); ++k) {
|
||||||
|
|||||||
@@ -91,11 +91,9 @@ bool check_filament_printable_after_group(const std::vector<unsigned int> &used_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return a zero based extruder from the region, or extruder_override if overriden.
|
// Return a zero based extruder from the region, or extruder_override if overriden.
|
||||||
// The region accessors below resolve mixed-color slots to the physical filament chosen for
|
// The region accessors below resolve mixed-color slots to the physical filament chosen for this
|
||||||
// this layer. Without sub-layer splitting a mixed slot is realized by alternating whole layers
|
// layer by resolve_mixed_filaments(), because a virtual slot id is never a real tool. resolve_mixed()
|
||||||
// (deficit round-robin, see resolve_mixed_filaments), so a region asking "which filament?" must
|
// returns its argument unchanged for every filament that is not a mixed slot.
|
||||||
// get the resolved physical one, not the virtual slot id. resolve_mixed() is identity when the
|
|
||||||
// slot is not mixed, so this is a no-op for every non-mixed setup.
|
|
||||||
unsigned int LayerTools::wall_extruder_id(const PrintRegion ®ion) const
|
unsigned int LayerTools::wall_extruder_id(const PrintRegion ®ion) const
|
||||||
{
|
{
|
||||||
assert(region.config().outer_wall_filament_id.value > 0);
|
assert(region.config().outer_wall_filament_id.value > 0);
|
||||||
@@ -2522,8 +2520,7 @@ void ToolOrdering::resolve_mixed_filaments(const PrintConfig &config)
|
|||||||
// - untagged region (modifier / painted / etc.) -> per_object_gradient[obj]
|
// - untagged region (modifier / painted / etc.) -> per_object_gradient[obj]
|
||||||
// Populating both keeps the per-object run state correct even when per-volume
|
// Populating both keeps the per-object run state correct even when per-volume
|
||||||
// takes over for the same (slot, obj), and lets untagged geometry (which is
|
// takes over for the same (slot, obj), and lets untagged geometry (which is
|
||||||
// explicitly NOT split per-volume in v1 per the design doc) keep its legacy
|
// never split per-volume) keep its per-object gradient ratios.
|
||||||
// per-object gradient ratios.
|
|
||||||
if (grp.is_gradient) {
|
if (grp.is_gradient) {
|
||||||
auto vol_runs_slot_it = per_vol_runs.find(ext);
|
auto vol_runs_slot_it = per_vol_runs.find(ext);
|
||||||
if (vol_runs_slot_it != per_vol_runs.end()) {
|
if (vol_runs_slot_it != per_vol_runs.end()) {
|
||||||
|
|||||||
@@ -309,9 +309,8 @@ Model Model::read_from_file(const std::string&
|
|||||||
ObjParser::MtlData mtl_data;
|
ObjParser::MtlData mtl_data;
|
||||||
result = load_obj(input_file.c_str(), &model, obj_info, message, nullptr, &mtl_data);
|
result = load_obj(input_file.c_str(), &model, obj_info, message, nullptr, &mtl_data);
|
||||||
if (result && obj_info.has_uv_png && !obj_info.uvs.empty() && !model.objects.empty()) {
|
if (result && obj_info.has_uv_png && !obj_info.uvs.empty() && !model.objects.empty()) {
|
||||||
// Textured OBJ: hand the mesh + materials to the texture-to-color importer instead
|
// Textured OBJ: hand the mesh + materials to the texture-to-color importer
|
||||||
// of the flat per-face colour dialog. Replaces Orca's previous "not implemented"
|
// instead of the flat per-face colour dialog.
|
||||||
// placeholder for this branch.
|
|
||||||
auto tex_mesh = std::make_shared<TexturedMesh>();
|
auto tex_mesh = std::make_shared<TexturedMesh>();
|
||||||
std::string obj_dir = boost::filesystem::path(input_file).parent_path().string();
|
std::string obj_dir = boost::filesystem::path(input_file).parent_path().string();
|
||||||
if (obj_to_textured_mesh(obj_info,
|
if (obj_to_textured_mesh(obj_info,
|
||||||
@@ -322,7 +321,7 @@ Model Model::read_from_file(const std::string&
|
|||||||
}
|
}
|
||||||
else if (result && !model.objects.empty() && !model.objects.back()->volumes.empty()) {
|
else if (result && !model.objects.empty() && !model.objects.back()->volumes.empty()) {
|
||||||
// Vertex-colour and MTL face-colour OBJs also go through the texture-to-color
|
// Vertex-colour and MTL face-colour OBJs also go through the texture-to-color
|
||||||
// importer (as precomputed per-face colors) instead of the legacy flat
|
// importer (as precomputed per-face colors) instead of the flat
|
||||||
// per-face colour dialog, matching the uv_png branch above.
|
// per-face colour dialog, matching the uv_png branch above.
|
||||||
auto build_tex_mesh_geometry = [&]() {
|
auto build_tex_mesh_geometry = [&]() {
|
||||||
auto tex_mesh = std::make_shared<TexturedMesh>();
|
auto tex_mesh = std::make_shared<TexturedMesh>();
|
||||||
@@ -374,7 +373,7 @@ Model Model::read_from_file(const std::string&
|
|||||||
else if (boost::algorithm::iends_with(input_file, ".glb") ||
|
else if (boost::algorithm::iends_with(input_file, ".glb") ||
|
||||||
boost::algorithm::iends_with(input_file, ".gltf") ||
|
boost::algorithm::iends_with(input_file, ".gltf") ||
|
||||||
boost::algorithm::iends_with(input_file, ".fbx")) {
|
boost::algorithm::iends_with(input_file, ".fbx")) {
|
||||||
// These formats always carry material/texture data, so they go through the textured
|
// These formats can carry material/texture data, so they go through the textured
|
||||||
// import path: the geometry becomes a normal object and the texture is handed to the
|
// import path: the geometry becomes a normal object and the texture is handed to the
|
||||||
// texture-to-color dialog via Model::texture_mesh.
|
// texture-to-color dialog via Model::texture_mesh.
|
||||||
auto tex_mesh = std::make_shared<TexturedMesh>();
|
auto tex_mesh = std::make_shared<TexturedMesh>();
|
||||||
|
|||||||
@@ -2715,19 +2715,13 @@ void PresetBundle::load_installed_sla_materials(AppConfig &config)
|
|||||||
preset.set_visible_from_appconfig(config);
|
preset.set_visible_from_appconfig(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mixed-color filament metadata is project state, carried in the 3mf's project_settings.config.
|
// Mixed-color filament metadata is project state saved in the 3mf, also mirrored into the app
|
||||||
// BambuStudio also snapshots it in the app config so the last session's mixes are back before any
|
// config so the last session's mixes are back before any project is opened. It is kept in the
|
||||||
// project is opened; there the filament list itself is a single global snapshot, so the mixed
|
// per-printer snapshot next to the filament list it indexes (filament_%02u/filament_colors),
|
||||||
// arrays live next to it in the global "presets" section. Orca's per-printer preset memory instead
|
// because that list is rebuilt on every printer selection and the component ids are 1-based
|
||||||
// rebuilds the filament list from the selected printer's snapshot (filament_%02u/filament_colors)
|
// indices into exactly that list. Missing keys clear the arrays, so one printer never inherits
|
||||||
// on startup AND on every printer selection — so the mixed arrays, whose component ids are 1-based
|
// another's mixes; fallback_to_global also reads the shared "presets" keys an older config
|
||||||
// indices into exactly that list, must live in the same per-printer snapshot or they end up
|
// layout used, which export_selections drops on the next save.
|
||||||
// describing a list they were never saved against (and previously got reset on every printer
|
|
||||||
// select, losing the mixes over a restart).
|
|
||||||
// Missing keys clear the arrays: a printer with no stored mixes must not inherit another's.
|
|
||||||
// fallback_to_global additionally reads the legacy shared "presets" keys (the old format) so a
|
|
||||||
// config saved by an earlier build still restores at startup; export_selections clears that
|
|
||||||
// section on the next save.
|
|
||||||
static void load_mixed_filament_settings(DynamicPrintConfig &project_config, AppConfig &config,
|
static void load_mixed_filament_settings(DynamicPrintConfig &project_config, AppConfig &config,
|
||||||
const std::string &printer_name, size_t n_filaments,
|
const std::string &printer_name, size_t n_filaments,
|
||||||
bool fallback_to_global)
|
bool fallback_to_global)
|
||||||
@@ -3162,12 +3156,9 @@ void PresetBundle::export_selections(AppConfig &config)
|
|||||||
"|");
|
"|");
|
||||||
config.set_printer_setting(printer_name, "flush_multiplier", flush_multiplier_str);
|
config.set_printer_setting(printer_name, "flush_multiplier", flush_multiplier_str);
|
||||||
|
|
||||||
// Mixed-color filament metadata: stored in the per-printer snapshot next to the filament
|
// Mixed-color filament metadata goes into the per-printer snapshot next to the filament list
|
||||||
// list it indexes (filament_%02u / filament_colors), so each printer's remembered config
|
// it indexes (see load_mixed_filament_settings). Bools are ','-joined and the component, ratio
|
||||||
// round-trips its own mixes and re-applying a snapshot never leaves the arrays describing a
|
// and range strings '|'-joined; the gradient curve is escaped instead, as it contains '|'.
|
||||||
// different list (see load_mixed_filament_settings). Bools are ','-joined; the
|
|
||||||
// component/ratio/range strings are '|'-joined; the gradient curve is escaped instead,
|
|
||||||
// because its values contain '|'.
|
|
||||||
auto join_bools = [](const std::vector<unsigned char> &vals) {
|
auto join_bools = [](const std::vector<unsigned char> &vals) {
|
||||||
std::string s;
|
std::string s;
|
||||||
for (size_t i = 0; i < vals.size(); ++i) {
|
for (size_t i = 0; i < vals.size(); ++i) {
|
||||||
@@ -3227,8 +3218,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::vector<std::string> ne
|
|||||||
ams_multi_color_filment.resize(n);
|
ams_multi_color_filment.resize(n);
|
||||||
|
|
||||||
// Mixed-color metadata is a parallel per-filament array set, so it has to grow and shrink
|
// Mixed-color metadata is a parallel per-filament array set, so it has to grow and shrink
|
||||||
// with the filament count exactly like filament_colour above. Missing this leaves the
|
// with the filament count exactly like filament_colour above.
|
||||||
// arrays short and every lookup of a newly created slot reads past the end.
|
|
||||||
if (auto* opt = project_config.option<ConfigOptionBools>("filament_is_mixed"))
|
if (auto* opt = project_config.option<ConfigOptionBools>("filament_is_mixed"))
|
||||||
opt->values.resize(n, false);
|
opt->values.resize(n, false);
|
||||||
if (auto* opt = project_config.option<ConfigOptionStrings>("filament_mixed_components"))
|
if (auto* opt = project_config.option<ConfigOptionStrings>("filament_mixed_components"))
|
||||||
@@ -3285,8 +3275,7 @@ void PresetBundle::set_num_filaments(unsigned int n, std::string new_color)
|
|||||||
ams_multi_color_filment.resize(n);
|
ams_multi_color_filment.resize(n);
|
||||||
|
|
||||||
// Mixed-color metadata is a parallel per-filament array set, so it has to grow and shrink
|
// Mixed-color metadata is a parallel per-filament array set, so it has to grow and shrink
|
||||||
// with the filament count exactly like filament_colour above. Missing this leaves the
|
// with the filament count exactly like filament_colour above.
|
||||||
// arrays short and every lookup of a newly created slot reads past the end.
|
|
||||||
if (auto* opt = project_config.option<ConfigOptionBools>("filament_is_mixed"))
|
if (auto* opt = project_config.option<ConfigOptionBools>("filament_is_mixed"))
|
||||||
opt->values.resize(n, false);
|
opt->values.resize(n, false);
|
||||||
if (auto* opt = project_config.option<ConfigOptionStrings>("filament_mixed_components"))
|
if (auto* opt = project_config.option<ConfigOptionStrings>("filament_mixed_components"))
|
||||||
|
|||||||
@@ -2615,12 +2615,9 @@ void Print::process(long long *time_cost_with_cache, bool use_cache)
|
|||||||
print_object_instances_ordering = sort_object_instances_by_model_order(*this);
|
print_object_instances_ordering = sort_object_instances_by_model_order(*this);
|
||||||
// A mixed slot is virtual; only its components reach a nozzle. These per-object orderings
|
// A mixed slot is virtual; only its components reach a nozzle. These per-object orderings
|
||||||
// are unsorted (no resolve_mixed_filaments), so expand the slots here for the grouping, the
|
// are unsorted (no resolve_mixed_filaments), so expand the slots here for the grouping, the
|
||||||
// unprintable sets and the slice-used lists. No-op without mixed filaments.
|
// unprintable sets and the slice-used lists. Because the expansion happens here rather than
|
||||||
// Orca: the slice-used lists stay sourced from these expanded lists rather than from the
|
// on the sorted orderings, the first-layer used set lists every component of a mixed slot,
|
||||||
// sorted orderings (which may add the wipe-tower filament or seed dontcare layers
|
// not just the one layer 0 resolves to. No-op without mixed filaments.
|
||||||
// differently), so prints without mixed filaments keep their used-filament set; the
|
|
||||||
// first-layer set therefore lists every component of a mixed slot, not just the one layer 0
|
|
||||||
// resolves to.
|
|
||||||
const auto &is_mixed = m_config.filament_is_mixed.values;
|
const auto &is_mixed = m_config.filament_is_mixed.values;
|
||||||
const auto &comp_strs = m_config.filament_mixed_components.values;
|
const auto &comp_strs = m_config.filament_mixed_components.values;
|
||||||
const bool has_mixed = has_any_mixed_filament(is_mixed);
|
const bool has_mixed = has_any_mixed_filament(is_mixed);
|
||||||
|
|||||||
@@ -1931,8 +1931,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
|||||||
for (const ModelVolume *volume : volumes) {
|
for (const ModelVolume *volume : volumes) {
|
||||||
const std::vector<bool> &volume_used_facet_states = volume->mmu_segmentation_facets.get_data().used_states;
|
const std::vector<bool> &volume_used_facet_states = volume->mmu_segmentation_facets.get_data().used_states;
|
||||||
|
|
||||||
// Sizes may legitimately differ: paint data stored before the state range was
|
// Paint data saved before the painted state range was extended deserializes a
|
||||||
// extended carries a shorter used_states vector. Merge over the common prefix.
|
// shorter used_states vector, so merge over the common prefix.
|
||||||
for (size_t state_idx = 0; state_idx < std::min(volume_used_facet_states.size(), used_facet_states.size()); ++state_idx)
|
for (size_t state_idx = 0; state_idx < std::min(volume_used_facet_states.size(), used_facet_states.size()); ++state_idx)
|
||||||
used_facet_states[state_idx] |= volume_used_facet_states[state_idx];
|
used_facet_states[state_idx] |= volume_used_facet_states[state_idx];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -639,9 +639,8 @@ static bool repair_cluster_smooth(
|
|||||||
{
|
{
|
||||||
TriangleMesh stats_mesh(static_cast<const indexed_triangle_set&>(mesh));
|
TriangleMesh stats_mesh(static_cast<const indexed_triangle_set&>(mesh));
|
||||||
const auto& stats = stats_mesh.stats();
|
const auto& stats = stats_mesh.stats();
|
||||||
// Orca's TriangleMeshStats defines manifold() as open_edges == 0 and does not track
|
// Orca's TriangleMeshStats only counts open edges: manifold() is open_edges == 0, and
|
||||||
// non-manifold edges/vertices separately, so BBS's "!manifold() || has_open_edges()"
|
// there are no separate non-manifold edge/vertex counters to test or log here.
|
||||||
// collapses to this single test and the extra counters drop out of the log.
|
|
||||||
if (!stats.manifold()) {
|
if (!stats.manifold()) {
|
||||||
BOOST_LOG_TRIVIAL(info) << log_prefix << ": mesh has non-manifold geometry or open boundaries, open_edges="
|
BOOST_LOG_TRIVIAL(info) << log_prefix << ": mesh has non-manifold geometry or open boundaries, open_edges="
|
||||||
<< stats.open_edges;
|
<< stats.open_edges;
|
||||||
|
|||||||
@@ -64,10 +64,9 @@ static constexpr double LARGE_BED_THRESHOLD = 2147;
|
|||||||
// Orca: maximum number of extruders is 64. For SEMM printers, it defines maximum filament number.
|
// Orca: maximum number of extruders is 64. For SEMM printers, it defines maximum filament number.
|
||||||
static constexpr size_t MAXIMUM_EXTRUDER_NUMBER = 64;
|
static constexpr size_t MAXIMUM_EXTRUDER_NUMBER = 64;
|
||||||
|
|
||||||
// Orca: how many filament slots syncing an AMS setup may create. This used to follow
|
// Orca: how many filament slots syncing an AMS setup may create. This was derived from
|
||||||
// EnforcerBlockerType::ExtruderMax, which capped it at the number of paintable filaments; that
|
// EnforcerBlockerType::ExtruderMax, but that cap now covers 32 paintable filaments, so the AMS
|
||||||
// limit has since been raised to 32, so the value is pinned here to keep AMS sync behaving as
|
// limit is pinned here to keep sync behaving as it does for projects without mixed-color filaments.
|
||||||
// before for projects that use no mixed-colour filaments.
|
|
||||||
static constexpr size_t MAXIMUM_AMS_SYNC_FILAMENT_NUMBER = 16;
|
static constexpr size_t MAXIMUM_AMS_SYNC_FILAMENT_NUMBER = 16;
|
||||||
|
|
||||||
// Orca: maximum line width is 5 times the nozzle diameter
|
// Orca: maximum line width is 5 times the nozzle diameter
|
||||||
|
|||||||
@@ -577,13 +577,9 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BBS
|
// BBS
|
||||||
// A filament override naming a slot that no longer exists is stale and falls back to the
|
// Reset filament overrides pointing at a slot that no longer exists. Support and the wipe
|
||||||
// plater's value. Support and the wipe tower are additionally restricted to physical filaments:
|
// tower additionally reject mixed slots: the engine consumes those keys directly, so a virtual
|
||||||
// the engine consumes those keys directly, with no per-layer mixed resolution, so a virtual
|
// slot would reach the G-code unresolved, while the per-feature keys are resolved per layer.
|
||||||
// slot there would reach the G-code unresolved. The per-feature keys have no such restriction —
|
|
||||||
// LayerTools::extruder() and its siblings resolve a mixed slot to the physical filament chosen
|
|
||||||
// for each layer. The sidebar dropdowns already hide mixed slots for the restricted keys
|
|
||||||
// (Plater.cpp DynamicFilamentList); this reset covers values loaded from projects.
|
|
||||||
static const char* physical_only_keys[] = { "support_filament", "support_interface_filament", "wipe_tower_filament" };
|
static const char* physical_only_keys[] = { "support_filament", "support_interface_filament", "wipe_tower_filament" };
|
||||||
static const char* feature_keys[] = { "outer_wall_filament_id", "inner_wall_filament_id",
|
static const char* feature_keys[] = { "outer_wall_filament_id", "inner_wall_filament_id",
|
||||||
"sparse_infill_filament_id", "internal_solid_filament_id",
|
"sparse_infill_filament_id", "internal_solid_filament_id",
|
||||||
|
|||||||
@@ -131,8 +131,7 @@ void fill_gradient_ramp_rect(wxDC& dc, const wxRect& rect, const std::vector<wxC
|
|||||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
for (int y = 0; y < rect.height; ++y) {
|
for (int y = 0; y < rect.height; ++y) {
|
||||||
// Row 0 is the top of the rect and so takes the ramp's last entry, the model's top.
|
// Row 0 is the top of the rect and so takes the ramp's last entry, the model's top.
|
||||||
// Mapping over height - 1 keeps both ends of the ramp on screen; a swatch is often
|
// Mapping over height - 1 puts both ends of the ramp on screen even in a short swatch.
|
||||||
// shorter than the ramp is long, so truncating either end would be visible.
|
|
||||||
const double t = (rect.height > 1) ? (double) (rect.height - 1 - y) / (rect.height - 1) : 0.5;
|
const double t = (rect.height > 1) ? (double) (rect.height - 1 - y) / (rect.height - 1) : 0.5;
|
||||||
dc.SetBrush(wxBrush(ramp[static_cast<size_t>(t * (ramp.size() - 1) + 0.5)]));
|
dc.SetBrush(wxBrush(ramp[static_cast<size_t>(t * (ramp.size() - 1) + 0.5)]));
|
||||||
dc.DrawRectangle(rect.x, rect.y + y, rect.width, 1);
|
dc.DrawRectangle(rect.x, rect.y + y, rect.width, 1);
|
||||||
|
|||||||
@@ -38,19 +38,17 @@ wxColour blend_n_colors(const std::vector<wxColour>& cols, const std::vector<dou
|
|||||||
|
|
||||||
// Sample a gradient mixed filament the way the slicer builds it: t runs 0..1 over the
|
// Sample a gradient mixed filament the way the slicer builds it: t runs 0..1 over the
|
||||||
// model's height, the curve gives the first component's ratio at t, and the two
|
// model's height, the curve gives the first component's ratio at t, and the two
|
||||||
// components are blended at that ratio. Entry 0 is the bottom of the model, the last
|
// components are blended at that ratio through blend_n_colors. Entry 0 is the bottom
|
||||||
// entry its top. Blending goes through blend_n_colors, so measured mixes and the
|
// of the model, the last entry its top.
|
||||||
// reserved [kGradientMinRatio, kGradientMaxRatio] band are both respected — a plain
|
|
||||||
// two-endpoint fade is neither.
|
|
||||||
std::vector<wxColour> sample_gradient_ramp(const wxColour& first,
|
std::vector<wxColour> sample_gradient_ramp(const wxColour& first,
|
||||||
const wxColour& second,
|
const wxColour& second,
|
||||||
const Slic3r::GradientCurve& curve,
|
const Slic3r::GradientCurve& curve,
|
||||||
int steps);
|
int steps);
|
||||||
|
|
||||||
// Same ramp for a project config slot, resolving components, colours and curve (or the
|
// Same ramp for a project config slot, resolving components, colours and curve (or the
|
||||||
// linear gradient_range fallback) from cfg. Empty unless the slot is a two-component
|
// linear gradient_range fallback) from cfg. Returns empty for any slot that is not a
|
||||||
// gradient mixed filament, which is what gates every caller to mixed slots only.
|
// two-component gradient mixed filament. steps is the ramp's resolution; pass the
|
||||||
// steps is the ramp's resolution; pass the destination's height in pixels.
|
// destination's height in pixels.
|
||||||
std::vector<wxColour> mixed_gradient_ramp(const Slic3r::DynamicPrintConfig& cfg, size_t slot, int steps);
|
std::vector<wxColour> mixed_gradient_ramp(const Slic3r::DynamicPrintConfig& cfg, size_t slot, int steps);
|
||||||
|
|
||||||
// Fill rect with a ramp, ramp.front() along the bottom edge.
|
// Fill rect with a ramp, ramp.front() along the bottom edge.
|
||||||
|
|||||||
@@ -9681,10 +9681,9 @@ void GLCanvas3D::_render_paint_toolbar() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ORCA: the loop above only produces a label for a slot whose preset is found in the preset
|
// ORCA: the loop above only labels a slot whose preset was found in the preset collection,
|
||||||
// collection, while the render loop below iterates extruder_num (= colour count). Pad the
|
// while the render loop below iterates extruder_num. Pad the label arrays so a slot without a
|
||||||
// label arrays so a slot without a matching preset cannot index past them — reading a garbage
|
// matching preset cannot index past them; a garbage std::string crashes ImGui::CalcTextSize.
|
||||||
// std::string here crashes in ImGui::CalcTextSize (strlen).
|
|
||||||
while (int(filament_text_first_line.size()) < extruder_num) {
|
while (int(filament_text_first_line.size()) < extruder_num) {
|
||||||
filament_text_first_line.emplace_back();
|
filament_text_first_line.emplace_back();
|
||||||
filament_text_second_line.emplace_back();
|
filament_text_second_line.emplace_back();
|
||||||
|
|||||||
@@ -8906,9 +8906,9 @@ void GUI_App::load_current_presets(bool active_preset_combox/*= false*/, bool ch
|
|||||||
auto* nozzle_diameter = edited_printer_preset.config.option<ConfigOptionFloats>("nozzle_diameter");
|
auto* nozzle_diameter = edited_printer_preset.config.option<ConfigOptionFloats>("nozzle_diameter");
|
||||||
if (nozzle_diameter) {
|
if (nozzle_diameter) {
|
||||||
// Mixed-color slots are virtual filaments kept at the tail of the list, so they have no
|
// Mixed-color slots are virtual filaments kept at the tail of the list, so they have no
|
||||||
// nozzle of their own. Sizing to the nozzle count alone truncates them away — and this
|
// nozzle of their own. Sizing to the nozzle count alone would silently drop the mixes of
|
||||||
// runs right after a project is loaded, so it would silently drop the project's mixes
|
// a just-loaded project, and update_extruder_count() would then strip the facets painted
|
||||||
// and then let update_extruder_count() strip every painted facet above the new count.
|
// with them.
|
||||||
preset_bundle->set_num_filaments(nozzle_diameter->values.size() + preset_bundle->num_mixed_filaments());
|
preset_bundle->set_num_filaments(nozzle_diameter->values.size() + preset_bundle->num_mixed_filaments());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3234,8 +3234,8 @@ void ObjectList::merge(bool to_multipart_object)
|
|||||||
void ObjectList::layers_editing()
|
void ObjectList::layers_editing()
|
||||||
{
|
{
|
||||||
// Height ranges give each range its own layer height, varying the mixed sub-layer heights just
|
// Height ranges give each range its own layer height, varying the mixed sub-layer heights just
|
||||||
// like an adaptive profile; sibling of the on_action_layersediting/ConfigManipulation warnings,
|
// like an adaptive profile, so this raises the same warning as variable layer height and shares
|
||||||
// sharing the same do-not-show-again flag.
|
// its do-not-show-again flag.
|
||||||
const auto& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
const auto& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||||
if (print_config.opt_bool("enable_mixed_color_sublayer")) {
|
if (print_config.opt_bool("enable_mixed_color_sublayer")) {
|
||||||
if (wxGetApp().app_config->get("no_warn_mixed_sublayer_variable_layer") != "1") {
|
if (wxGetApp().app_config->get("no_warn_mixed_sublayer_variable_layer") != "1") {
|
||||||
|
|||||||
@@ -326,10 +326,9 @@ bool GLGizmoMmuSegmentation::draw_color_button(int idx, const char* id_str, cons
|
|||||||
bool dark_tone = gradient ? (*gradient)[gradient->size() / 2].GetLuminance() < 0.51 :
|
bool dark_tone = gradient ? (*gradient)[gradient->size() / 2].GetLuminance() < 0.51 :
|
||||||
(0.299f * color.r() + 0.587f * color.g() + 0.114f * color.b()) < 0.51f; // matching values used by wxWidgets with clr.GetLuminance() < 0.51
|
(0.299f * color.r() + 0.587f * color.g() + 0.114f * color.b()) < 0.51f; // matching values used by wxWidgets with clr.GetLuminance() < 0.51
|
||||||
|
|
||||||
// Paint a gradient mixed filament's fade before the button and keep the button transparent, so the
|
// Paint a gradient mixed filament's fade before the button and keep the button transparent, so
|
||||||
// slot number and the frame below stay on top of it. The bands cannot round their corners, so the
|
// the slot number and the frame below stay on top of it. The bands cannot round their corners,
|
||||||
// fade is drawn at the frame's inset and the frame masks it into the same shape a plain color slot
|
// so the fade is inset to the frame, which masks it into the shape a plain color slot gets.
|
||||||
// gets.
|
|
||||||
if (gradient) {
|
if (gradient) {
|
||||||
ImGuiWrapper::draw_gradient_ramp(draw_list, {pos.x + frame_inset * scale, pos.y + frame_inset * scale},
|
ImGuiWrapper::draw_gradient_ramp(draw_list, {pos.x + frame_inset * scale, pos.y + frame_inset * scale},
|
||||||
{pos.x + size.x - frame_inset * scale, pos.y + size.y - frame_inset * scale}, *gradient);
|
{pos.x + size.x - frame_inset * scale, pos.y + size.y - frame_inset * scale}, *gradient);
|
||||||
@@ -778,7 +777,7 @@ void GLGizmoMmuSegmentation::update_triangle_selectors_colors()
|
|||||||
TriangleSelectorPatch* selector = dynamic_cast<TriangleSelectorPatch*>(m_triangle_selectors[i].get());
|
TriangleSelectorPatch* selector = dynamic_cast<TriangleSelectorPatch*>(m_triangle_selectors[i].get());
|
||||||
int extruder_idx = m_volumes_extruder_idxs[i];
|
int extruder_idx = m_volumes_extruder_idxs[i];
|
||||||
int extruder_color_idx = std::max(0, extruder_idx - 1);
|
int extruder_color_idx = std::max(0, extruder_idx - 1);
|
||||||
// As above: a mixed-color slot can index past the physical colour list.
|
// A mixed-color slot can index past the physical colour list; fall back to the first colour.
|
||||||
if (extruder_color_idx >= (int)m_extruders_colors.size())
|
if (extruder_color_idx >= (int)m_extruders_colors.size())
|
||||||
extruder_color_idx = 0;
|
extruder_color_idx = 0;
|
||||||
std::vector<ColorRGBA> ebt_colors;
|
std::vector<ColorRGBA> ebt_colors;
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ private:
|
|||||||
// ORCA
|
// ORCA
|
||||||
bool draw_color_button(int idx, const char* id_str, const ColorRGBA& color, ColorRGBA& map_color, bool active, float scale);
|
bool draw_color_button(int idx, const char* id_str, const ColorRGBA& color, ColorRGBA& map_color, bool active, float scale);
|
||||||
// Gradient ramp of a filament slot, or nullptr when the slot is a plain single color
|
// Gradient ramp of a filament slot, or nullptr when the slot is a plain single color
|
||||||
// filament, so callers can index into what they get back freely.
|
// filament. A non-null result is never empty.
|
||||||
const std::vector<wxColour>* gradient_of(int idx) const
|
const std::vector<wxColour>* gradient_of(int idx) const
|
||||||
{
|
{
|
||||||
return idx >= 0 && idx < (int) m_gradient_ramps.size() && !m_gradient_ramps[idx].empty() ? &m_gradient_ramps[idx] : nullptr;
|
return idx >= 0 && idx < (int) m_gradient_ramps.size() && !m_gradient_ramps[idx].empty() ? &m_gradient_ramps[idx] : nullptr;
|
||||||
|
|||||||
@@ -998,8 +998,8 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
|||||||
keyCode = keyCode- WXK_NUMPAD0+'0';
|
keyCode = keyCode- WXK_NUMPAD0+'0';
|
||||||
}
|
}
|
||||||
if (keyCode >= '0' && keyCode <= '9') {
|
if (keyCode >= '0' && keyCode <= '9') {
|
||||||
// The paint palette now reaches EXTRUDERS_LIMIT (mixed-color filaments share
|
// The paint palette reaches EXTRUDERS_LIMIT slots (mixed-color filaments take
|
||||||
// the same slots), so any leading digit that can start a valid two-digit
|
// ordinary slots too), so any leading digit that can start a valid two-digit
|
||||||
// number waits briefly for a second one.
|
// number waits briefly for a second one.
|
||||||
const int digit = keyCode - '0';
|
const int digit = keyCode - '0';
|
||||||
const int shortcut_max = int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT);
|
const int shortcut_max = int(GLGizmoMmuSegmentation::EXTRUDERS_LIMIT);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace GUI {
|
|||||||
wxDEFINE_EVENT(wxEVT_GRADIENT_CURVE_CHANGED, wxCommandEvent);
|
wxDEFINE_EVENT(wxEVT_GRADIENT_CURVE_CHANGED, wxCommandEvent);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Layout (Figma "Property 1=Default", 214.06 x 179.63 px reference).
|
// Layout ratios of the plot rect within the widget, taken from a 214 x 180 px reference drawing.
|
||||||
// Plot rect occupies the upper-left region; right + bottom margins host axis arrows / labels.
|
// Plot rect occupies the upper-left region; right + bottom margins host axis arrows / labels.
|
||||||
constexpr double kPlotLeftRatio = 0.0316;
|
constexpr double kPlotLeftRatio = 0.0316;
|
||||||
constexpr double kPlotRightRatio = 0.6766;
|
constexpr double kPlotRightRatio = 0.6766;
|
||||||
@@ -37,7 +37,7 @@ constexpr int kStrokeAxis = 2; // axis line width (px, no DPI scaling -
|
|||||||
constexpr int kAxisArrowHalf = 5; // half-base of the axis arrow triangle (DIP)
|
constexpr int kAxisArrowHalf = 5; // half-base of the axis arrow triangle (DIP)
|
||||||
constexpr int kAxisArrowLen = 10; // length of the axis arrow triangle (DIP)
|
constexpr int kAxisArrowLen = 10; // length of the axis arrow triangle (DIP)
|
||||||
|
|
||||||
// Light-mode design tokens from Figma. Resolved through StateColor::darkModeColorFor()
|
// Light-mode design tokens. Resolved through StateColor::darkModeColorFor()
|
||||||
// at paint time so the editor follows the app theme (#EEEEEE -> #4C4C55, #6B6B6B ->
|
// at paint time so the editor follows the app theme (#EEEEEE -> #4C4C55, #6B6B6B ->
|
||||||
// #818183, #262E30 -> #EFEFF0, *wxWHITE -> #2D2D31). Don't read these directly in paint;
|
// #818183, #262E30 -> #EFEFF0, *wxWHITE -> #2D2D31). Don't read these directly in paint;
|
||||||
// always go through the resolved locals declared at the top of on_paint().
|
// always go through the resolved locals declared at the top of on_paint().
|
||||||
@@ -46,11 +46,9 @@ const wxColour kAxisColor (107, 107, 107); // #6B6B6B grey 700
|
|||||||
const wxColour kLabelMuted (107, 107, 107); // #6B6B6B grey 700
|
const wxColour kLabelMuted (107, 107, 107); // #6B6B6B grey 700
|
||||||
const wxColour kLabelStrong ( 38, 46, 48); // #262E30 grey 900
|
const wxColour kLabelStrong ( 38, 46, 48); // #262E30 grey 900
|
||||||
|
|
||||||
// LAB (DeltaE76) threshold for "curve color is too close to the background". Below this
|
// LAB (DeltaE76) threshold for "curve color is too close to the background": below it the curve
|
||||||
// we paint a subtle axis-color outline so the curve doesn't visually vanish; above this
|
// gets a subtle outline so it does not visually vanish, otherwise it is drawn plain. Looser than
|
||||||
// we draw the curve plain. ~15 is "perceptible but still close", looser than the strict
|
// the 5.0 of FlushPredict::is_similar_color, so a pastel pink on white still gets an outline.
|
||||||
// 5.0 used by FlushPredict::is_similar_color but loose enough that a pastel pink on white
|
|
||||||
// or a charcoal on #2B2B2B still triggers an outline.
|
|
||||||
constexpr float kBgSimilarThreshold = 15.0f;
|
constexpr float kBgSimilarThreshold = 15.0f;
|
||||||
constexpr int kOutlineExtraDip = 2;
|
constexpr int kOutlineExtraDip = 2;
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -65,8 +63,6 @@ GradientCurveEditor::GradientCurveEditor(wxWindow* parent,
|
|||||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||||
SetBackgroundColour(wxGetApp().get_window_default_clr());
|
SetBackgroundColour(wxGetApp().get_window_default_clr());
|
||||||
// Wide enough so the X-axis "Material Ratio" label fits past the arrow tip without overlap.
|
// Wide enough so the X-axis "Material Ratio" label fits past the arrow tip without overlap.
|
||||||
// 260 (was 240): adds room for the "Material Ratio" label that gets shifted right by the
|
|
||||||
// longer axis arrow; the hosting MixedFilamentDialog grows to 470 DIP to accommodate.
|
|
||||||
SetMinSize(FromDIP(wxSize(260, 200)));
|
SetMinSize(FromDIP(wxSize(260, 200)));
|
||||||
|
|
||||||
reset_to_linear(0.10, 0.90);
|
reset_to_linear(0.10, 0.90);
|
||||||
@@ -456,10 +452,9 @@ void GradientCurveEditor::on_paint(wxPaintEvent& /*evt*/)
|
|||||||
return poly;
|
return poly;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only the geometry goes through the graphics context: dc.DrawLines() takes integer
|
// Only the geometry goes through the graphics context: dc.DrawLines() takes integer wxPoint
|
||||||
// wxPoint and would quantize the curve back to whole pixels. The pen is still set on
|
// and would quantize the curve back to whole pixels. The pen is still set on the dc, which
|
||||||
// the dc, which forwards it to this same context while keeping the dc's own cached
|
// forwards it here while keeping its own cached state in sync for later dc drawing.
|
||||||
// state in sync, so later dc drawing does not inherit the curve's pen.
|
|
||||||
auto draw_polyline = [&](const std::vector<wxPoint2DDouble>& poly, const wxColour& col, int stroke_dip) {
|
auto draw_polyline = [&](const std::vector<wxPoint2DDouble>& poly, const wxColour& col, int stroke_dip) {
|
||||||
dc.SetPen(wxPen(col, FromDIP(stroke_dip)));
|
dc.SetPen(wxPen(col, FromDIP(stroke_dip)));
|
||||||
gc->StrokeLines(poly.size(), poly.data());
|
gc->StrokeLines(poly.size(), poly.data());
|
||||||
@@ -552,12 +547,9 @@ void GradientCurveEditor::on_left_down(wxMouseEvent& evt)
|
|||||||
|
|
||||||
// 4) Selected curve line body hit -> insert a new anchor at cursor x (snapped
|
// 4) Selected curve line body hit -> insert a new anchor at cursor x (snapped
|
||||||
// to the current smooth curve so the initial click is visually invisible)
|
// to the current smooth curve so the initial click is visually invisible)
|
||||||
// and immediately enter Anchor drag mode. PS Curves style: the drag-bend
|
// and immediately enter Anchor drag mode. Bending the segment without
|
||||||
// interaction has no separate "bend without anchor" mode; pressing and
|
// inserting an anchor is not an option: a single cubic between two existing
|
||||||
// dragging on the line is equivalent to clicking to add then dragging the
|
// anchors cannot put its peak under an off-center cursor.
|
||||||
// fresh anchor. Trades the previous (failed) "no anchor on drag" promise
|
|
||||||
// for genuine cursor tracking, since a single cubic between two existing
|
|
||||||
// anchors mathematically cannot put its peak under an off-center cursor.
|
|
||||||
double nx = 0, dummy = 0;
|
double nx = 0, dummy = 0;
|
||||||
px_to_data(pos.x, pos.y, nx, dummy);
|
px_to_data(pos.x, pos.y, nx, dummy);
|
||||||
if (nx <= 0.0 || nx >= 1.0 || seg < 0) {
|
if (nx <= 0.0 || nx >= 1.0 || seg < 0) {
|
||||||
|
|||||||
@@ -894,9 +894,9 @@ wxBoxSizer* MixedFilamentDialog::create_ratio_slider()
|
|||||||
on_ratio_changed(std::max(MIN_COMPONENT_RATIO, std::min(100 - MIN_COMPONENT_RATIO, new_ratio)));
|
on_ratio_changed(std::max(MIN_COMPONENT_RATIO, std::min(100 - MIN_COMPONENT_RATIO, new_ratio)));
|
||||||
});
|
});
|
||||||
|
|
||||||
// Release whenever the capture is held, not only when the drag flag is set:
|
// Key the release off the capture itself, not off the drag flag: the two can fall out of
|
||||||
// the flag can be cleared behind our back, and a capture that outlives the
|
// sync (a lost capture clears the flag on its own), and a capture that outlives the widget
|
||||||
// widget wedges mouse input for the whole application.
|
// wedges mouse input for the whole application.
|
||||||
m_ratio_bar->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent&) {
|
m_ratio_bar->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent&) {
|
||||||
m_ratio_dragging = false;
|
m_ratio_dragging = false;
|
||||||
if (m_ratio_bar->HasCapture())
|
if (m_ratio_bar->HasCapture())
|
||||||
@@ -1492,11 +1492,9 @@ void MixedFilamentDialog::on_ratio_changed(int new_ratio_a)
|
|||||||
|
|
||||||
void MixedFilamentDialog::on_gradient_toggled()
|
void MixedFilamentDialog::on_gradient_toggled()
|
||||||
{
|
{
|
||||||
// Orca: the engine only produces a gradient when the print profile's
|
// Orca: a gradient is only sliced when the print profile's "enable_mixed_color_sublayer"
|
||||||
// "enable_mixed_color_sublayer" option is on (ToolOrdering::resolve_mixed_filaments
|
// option is on; without it ToolOrdering picks a single component per whole layer. Offer to
|
||||||
// falls back to whole-layer round-robin without it, and BBS leaves users to find the
|
// turn the option on instead of silently ignoring the gradient the user just enabled.
|
||||||
// option themselves). Offer to switch it on so the gradient the user just enabled
|
|
||||||
// actually shows up in the sliced result. Keep this block on future BBS syncs.
|
|
||||||
bool checked = m_chk_gradient->GetValue();
|
bool checked = m_chk_gradient->GetValue();
|
||||||
|
|
||||||
if (checked) {
|
if (checked) {
|
||||||
|
|||||||
@@ -2048,13 +2048,8 @@ bool PartPlate::check_tpu_printable_status(const DynamicPrintConfig & config, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A mixed-color filament alternates between its components constantly. On a single-nozzle
|
// A mixed-color filament alternates between its components constantly. On a single-nozzle
|
||||||
// printer every one of those switches is a full filament change plus a purge, so warn the
|
// printer every one of those switches is a full filament change plus a purge, so warn before
|
||||||
// user before they commit to it. Printers with more than one nozzle can keep the components
|
// slicing. Multi-nozzle printers keep the components loaded at once and are not affected.
|
||||||
// loaded simultaneously and are not affected.
|
|
||||||
//
|
|
||||||
// BBS additionally excludes its H2C/H2D/X2D models by name; those are multi-nozzle machines
|
|
||||||
// already ruled out by the nozzle_diameter test above, so the name check is dropped here
|
|
||||||
// rather than carried over as a Bambu-specific special case.
|
|
||||||
bool PartPlate::check_single_extruder_mixed_filament_risk(const DynamicPrintConfig &config, std::string &warning_text) const
|
bool PartPlate::check_single_extruder_mixed_filament_risk(const DynamicPrintConfig &config, std::string &warning_text) const
|
||||||
{
|
{
|
||||||
warning_text.clear();
|
warning_text.clear();
|
||||||
|
|||||||
@@ -473,8 +473,7 @@ PlateSettingsDialog::PlateSettingsDialog(wxWindow* parent, const wxString& title
|
|||||||
m_sizer_main->Add(m_other_layers_seq_panel, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));
|
m_sizer_main->Add(m_other_layers_seq_panel, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));
|
||||||
|
|
||||||
// A mixed-color slot resolves to a different physical filament per layer, so a user-defined
|
// A mixed-color slot resolves to a different physical filament per layer, so a user-defined
|
||||||
// filament order cannot be honoured. Disable the choice and say why. BBS puts this warning
|
// filament order cannot be honoured; grey out the choice and explain that in the dialog.
|
||||||
// inside its button sizer; Orca builds the buttons with DialogButtons, so it gets its own row.
|
|
||||||
{
|
{
|
||||||
auto &proj_cfg = wxGetApp().preset_bundle->project_config;
|
auto &proj_cfg = wxGetApp().preset_bundle->project_config;
|
||||||
auto *is_mixed_opt = proj_cfg.option<ConfigOptionBools>("filament_is_mixed");
|
auto *is_mixed_opt = proj_cfg.option<ConfigOptionBools>("filament_is_mixed");
|
||||||
|
|||||||
+14
-22
@@ -3876,10 +3876,8 @@ void Sidebar::change_top_border_for_mode_sizer(bool increase_border)
|
|||||||
|
|
||||||
|
|
||||||
// ---- Mixed-color filament sidebar support ----
|
// ---- Mixed-color filament sidebar support ----
|
||||||
// Ported from BambuStudio's 混色耗材 feature. BBS hosts these widgets in an
|
// The mixed rows get their own scroll area, capped by Orca's filaments_area_preferred_count
|
||||||
// m_filament_area_wrapper that Orca's sidebar has no counterpart for, so the mixed
|
// row budget rather than BBS's fixed 3-row / 12-filament limit.
|
||||||
// section is parented to p->scrolled and sized with Orca's own row-height preference
|
|
||||||
// (filaments_area_preferred_count) rather than BBS's fixed 3-row / 12-filament cap.
|
|
||||||
void Sidebar::recalc_filament_scroll_sizes()
|
void Sidebar::recalc_filament_scroll_sizes()
|
||||||
{
|
{
|
||||||
if (!p->m_mixed_scroll_area || !p->m_mixed_scroll_area->GetSizer())
|
if (!p->m_mixed_scroll_area || !p->m_mixed_scroll_area->GetSizer())
|
||||||
@@ -4102,8 +4100,8 @@ void Sidebar::update_mixed_filament_list()
|
|||||||
unsigned int mix_num = (unsigned int)(cfg_idx + 1);
|
unsigned int mix_num = (unsigned int)(cfg_idx + 1);
|
||||||
|
|
||||||
// The swatch fades bottom to top over the model's height, sampled the same way
|
// The swatch fades bottom to top over the model's height, sampled the same way
|
||||||
// the slicer builds the sublayers, so it matches the editor's Effect Preview. It
|
// the slicer builds the sublayers, so it matches the editor's Effect Preview. The
|
||||||
// comes back empty for every slot that is not a two component gradient mix.
|
// ramp comes back empty for every slot that is not a two component gradient mix.
|
||||||
const int swatch_sz = FromDIP(20);
|
const int swatch_sz = FromDIP(20);
|
||||||
const std::vector<wxColour> gradient_ramp = mixed_gradient_ramp(project_config, cfg_idx, swatch_sz);
|
const std::vector<wxColour> gradient_ramp = mixed_gradient_ramp(project_config, cfg_idx, swatch_sz);
|
||||||
|
|
||||||
@@ -4642,9 +4640,8 @@ static bool create_mixed_filament_from_result(
|
|||||||
multi_colour_opt->values[new_idx] = mixed_color;
|
multi_colour_opt->values[new_idx] = mixed_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set_num_filaments() above is what grows these parallel arrays. Guard the writes anyway,
|
// set_num_filaments() above already grows these parallel arrays; the writes are still
|
||||||
// matching the gradient writes below, so a sizing bug degrades into a no-op rather than a
|
// size-guarded so a sizing bug degrades into a no-op rather than a heap overwrite.
|
||||||
// heap overwrite.
|
|
||||||
{
|
{
|
||||||
auto* is_mixed_opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
|
auto* is_mixed_opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
|
||||||
while (is_mixed_opt->values.size() <= new_idx) is_mixed_opt->values.push_back(false);
|
while (is_mixed_opt->values.size() <= new_idx) is_mixed_opt->values.push_back(false);
|
||||||
@@ -14071,11 +14068,9 @@ bool Plater::priv::can_layers_editing() const
|
|||||||
|
|
||||||
void Plater::priv::on_action_layersediting(SimpleEvent&)
|
void Plater::priv::on_action_layersediting(SimpleEvent&)
|
||||||
{
|
{
|
||||||
// Sub-layer splitting divides each layer by the mix ratio, so an adaptive layer profile makes
|
// Sub-layer splitting divides each layer by the mix ratio, so a variable layer height profile
|
||||||
// those sub-layer heights vary and degrades the blend. ConfigManipulation warns when the
|
// makes those sub-layer heights uneven and degrades the blend. ConfigManipulation warns for the
|
||||||
// option is switched on with a variable profile already present; this is the other direction,
|
// opposite order, when the option is switched on while a variable profile already exists.
|
||||||
// warning when variable layer editing is switched on while the option is active. All three
|
|
||||||
// sites (with ObjectList::layers_editing for height ranges) honour the same do-not-show-again flag.
|
|
||||||
if (!view3D->is_layers_editing_enabled()) {
|
if (!view3D->is_layers_editing_enabled()) {
|
||||||
const auto& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
const auto& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||||
if (print_config.opt_bool("enable_mixed_color_sublayer")) {
|
if (print_config.opt_bool("enable_mixed_color_sublayer")) {
|
||||||
@@ -19988,14 +19983,11 @@ std::vector<std::string> Plater::get_filament_color_render_type() const
|
|||||||
|
|
||||||
const std::vector<std::vector<wxColour>>& Plater::get_filament_gradient_ramps() const
|
const std::vector<std::vector<wxColour>>& Plater::get_filament_gradient_ramps() const
|
||||||
{
|
{
|
||||||
// Sampling a ramp walks the measured-blend recipe table once per step, and the paint toolbar
|
// Sampling a ramp walks the measured-blend recipe table once per step and the paint toolbar
|
||||||
// asks for the ramps on every rendered frame, so they are cached against the config values
|
// asks for the ramps every rendered frame, so they are cached against the config values they
|
||||||
// they are built from and resampled only when one of those actually changes.
|
// are built from. The cache is static rather than a Plater member because the extruder icons
|
||||||
//
|
// ask for the ramps from MenuFactory::init(), which runs while this Plater is still inside its
|
||||||
// The cache cannot live on the Plater: the extruder icons ask for the ramps from inside
|
// own constructor, so wxGetApp().plater_ is not assigned yet.
|
||||||
// MenuFactory::init(), which runs while this Plater is still being constructed, so `this` is
|
|
||||||
// not usable yet. Everything the ramps are built from is global anyway, and there is one
|
|
||||||
// Plater per process, which is the same reasoning behind the icons' own static BitmapCache.
|
|
||||||
static std::string s_ramps_key;
|
static std::string s_ramps_key;
|
||||||
static std::vector<std::vector<wxColour>> s_ramps;
|
static std::vector<std::vector<wxColour>> s_ramps;
|
||||||
|
|
||||||
|
|||||||
@@ -2577,7 +2577,7 @@ void SyncAmsInfoDialog::reset_and_sync_ams_list()
|
|||||||
m_filaments.clear();
|
m_filaments.clear();
|
||||||
|
|
||||||
// Mixed-color slots are virtual: they never occupy a tray, so they must not appear as
|
// Mixed-color slots are virtual: they never occupy a tray, so they must not appear as
|
||||||
// AMS sync targets. Look the flags up once and skip those slots in the loop below.
|
// AMS sync targets.
|
||||||
auto* is_mixed_opt = preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed");
|
auto* is_mixed_opt = preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed");
|
||||||
|
|
||||||
bool use_double_extruder = get_is_double_extruder();
|
bool use_double_extruder = get_is_double_extruder();
|
||||||
@@ -2801,7 +2801,7 @@ void SyncAmsInfoDialog::generate_override_fix_ams_list()
|
|||||||
m_fix_filaments.clear();
|
m_fix_filaments.clear();
|
||||||
|
|
||||||
// Mixed-color slots are virtual: they never occupy a tray, so they must not appear as
|
// Mixed-color slots are virtual: they never occupy a tray, so they must not appear as
|
||||||
// AMS sync targets. Look the flags up once and skip those slots in the loop below.
|
// AMS sync targets.
|
||||||
auto* is_mixed_opt = preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed");
|
auto* is_mixed_opt = preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed");
|
||||||
|
|
||||||
bool use_double_extruder = get_is_double_extruder();
|
bool use_double_extruder = get_is_double_extruder();
|
||||||
|
|||||||
@@ -1368,11 +1368,9 @@ void TexturePreviewCanvas::ensure_gl_ready()
|
|||||||
{
|
{
|
||||||
if (m_gl_initialized) return;
|
if (m_gl_initialized) return;
|
||||||
|
|
||||||
// BBS loads GL entry points here with GLEW. Orca uses glad and centralises loading in
|
// BBS loads the GL entry points here with GLEW; Orca loads them centrally in
|
||||||
// OpenGLManager, which has already run by the time any canvas is realized, so just
|
// OpenGLManager, so only check that this has already happened (glad leaves unresolved
|
||||||
// verify the loader is up and drain any stale error state.
|
// entry points null) and drain any stale error state.
|
||||||
// glad leaves unresolved entry points as null pointers, so this is a cheap guard against
|
|
||||||
// painting before OpenGLManager::init_gl() has run.
|
|
||||||
if (glGetString == nullptr) {
|
if (glGetString == nullptr) {
|
||||||
BOOST_LOG_TRIVIAL(error) << "TexturePreviewCanvas: OpenGL functions are not loaded yet";
|
BOOST_LOG_TRIVIAL(error) << "TexturePreviewCanvas: OpenGL functions are not loaded yet";
|
||||||
return;
|
return;
|
||||||
@@ -2436,10 +2434,9 @@ void TextureImportDialog::start_computation(bool auto_color, bool initial)
|
|||||||
settings.target_colors_num = auto_color ? 0 : (size_t)m_param_color_count;
|
settings.target_colors_num = auto_color ? 0 : (size_t)m_param_color_count;
|
||||||
settings.smooth_weight = m_param_smooth / 10.0;
|
settings.smooth_weight = m_param_smooth / 10.0;
|
||||||
settings.mesh_repair_decision = m_mesh_repair_decision;
|
settings.mesh_repair_decision = m_mesh_repair_decision;
|
||||||
// BBS repairs the mesh through the Windows 3D SDK, which only exists on Windows and only
|
// BBS repairs the mesh through the Windows 3D SDK, which is only available on Windows
|
||||||
// when the SDK is present at build time. Orca already ships a CGAL-based repair
|
// builds that ship the SDK. Orca's CGAL-based repair (MeshBoolean::cgal::repair) works
|
||||||
// (MeshBoolean::cgal::repair) that works on all three platforms, so use that instead —
|
// on all three platforms, so use that instead.
|
||||||
// this makes the repair path available on Linux and macOS too.
|
|
||||||
settings.mesh_repair_callback = [](const indexed_triangle_set& mesh,
|
settings.mesh_repair_callback = [](const indexed_triangle_set& mesh,
|
||||||
indexed_triangle_set& repaired_mesh,
|
indexed_triangle_set& repaired_mesh,
|
||||||
std::function<void(const char*, unsigned)> progress_callback,
|
std::function<void(const char*, unsigned)> progress_callback,
|
||||||
|
|||||||
@@ -360,8 +360,7 @@ void DropDown::render(wxDC &dc)
|
|||||||
for (int i = 0; i < items.size(); ++i) {
|
for (int i = 0; i < items.size(); ++i) {
|
||||||
auto &item = items[i];
|
auto &item = items[i];
|
||||||
int states2 = states;
|
int states2 = states;
|
||||||
// Dimmed items stay selectable but render greyed out (used by the mixed-filament
|
// Dimmed items render greyed out but stay selectable, so they cannot reuse the disabled state.
|
||||||
// dialog to show components that are already consumed by another mix).
|
|
||||||
bool is_dimmed = (item.style & DD_ITEM_STYLE_DIMMED) != 0;
|
bool is_dimmed = (item.style & DD_ITEM_STYLE_DIMMED) != 0;
|
||||||
if ((item.style & DD_ITEM_STYLE_DISABLED) != 0)
|
if ((item.style & DD_ITEM_STYLE_DISABLED) != 0)
|
||||||
states2 &= ~StateColor::Enabled;
|
states2 &= ~StateColor::Enabled;
|
||||||
|
|||||||
@@ -261,10 +261,9 @@ static std::vector<float> MatrixFlatten(const WipingDialog::VolumeMatrix& matrix
|
|||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mixed-color slots are virtual: they are never loaded into a tray and so have no flushing
|
// Mixed-color slots are virtual and have no flushing volumes, so the dialog shows only the
|
||||||
// volumes of their own. The dialog therefore shows only the physical filaments, which means
|
// physical filaments. That means converting between the full config matrix (indexed by config
|
||||||
// converting between the full config matrix (indexed by config slot) and a dense physical
|
// slot) and a dense physical sub-matrix (indexed by row/column in the table).
|
||||||
// sub-matrix (indexed by row/column in the table).
|
|
||||||
static std::vector<double> extract_physical_sub_matrix(
|
static std::vector<double> extract_physical_sub_matrix(
|
||||||
const std::vector<double>& full_matrix, size_t full_n,
|
const std::vector<double>& full_matrix, size_t full_n,
|
||||||
const std::vector<size_t>& indices)
|
const std::vector<size_t>& indices)
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ DynamicPrintConfig mixed_config(bool sublayer_on, const char *ratios = "0.6,0.4"
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Total sub-layer groups and per-layer DRR resolutions across the whole tool ordering.
|
// Total sub-layer groups and per-layer mixed-filament resolutions across the whole tool ordering.
|
||||||
void count_mixed(ToolOrdering &to, size_t &groups, size_t &resolutions)
|
void count_mixed(ToolOrdering &to, size_t &groups, size_t &resolutions)
|
||||||
{
|
{
|
||||||
groups = resolutions = 0;
|
groups = resolutions = 0;
|
||||||
@@ -139,9 +139,8 @@ TEST_CASE("Whole-layer mixing emits only the nominal layer height", "[MixedFilam
|
|||||||
|
|
||||||
TEST_CASE("By-object prints without mixed filaments keep their used-filament set", "[MixedFilament]")
|
TEST_CASE("By-object prints without mixed filaments keep their used-filament set", "[MixedFilament]")
|
||||||
{
|
{
|
||||||
// Regression guard for the mixed gate: with no mixed slot the by-object bookkeeping must
|
// With no mixed slot the by-object bookkeeping stays plain: object 2 prints with filament 2,
|
||||||
// be untouched by this change. Object 2 prints with filament 2, so both filaments are used
|
// so both filaments are used and no mixed filament is reported.
|
||||||
// and no mixed filament is reported.
|
|
||||||
DynamicPrintConfig config = multifilament_config(2, {{"print_sequence", "by object"}});
|
DynamicPrintConfig config = multifilament_config(2, {{"print_sequence", "by object"}});
|
||||||
const std::vector<std::vector<ConfigBase::SetDeserializeItem>> overrides{ {}, { {"extruder", "2"} } };
|
const std::vector<std::vector<ConfigBase::SetDeserializeItem>> overrides{ {}, { {"extruder", "2"} } };
|
||||||
|
|
||||||
|
|||||||
@@ -501,10 +501,8 @@ SCENARIO("Nozzle-group metadata .3mf round-trip", "[3mf][MultiNozzle]") {
|
|||||||
|
|
||||||
|
|
||||||
// A mixed-color filament occupies an ordinary filament slot, and painting with it stores an
|
// A mixed-color filament occupies an ordinary filament slot, and painting with it stores an
|
||||||
// ordinary extruder state — a project saved by BambuStudio encodes filament 5 of a 5-slot setup
|
// ordinary extruder state: a project saved by BambuStudio encodes filament 5 of a 5-slot setup
|
||||||
// as paint state 5, with the mix described by the parallel filament_mixed_* project arrays. This
|
// as paint state 5, with the mix described by the parallel filament_mixed_* project arrays.
|
||||||
// pins both halves of that contract at the .3mf layer: the project keys and the painted states
|
|
||||||
// must come back exactly as written.
|
|
||||||
SCENARIO("Mixed-color filament setup and painting round-trip through a .3mf", "[3mf][MixedFilament]") {
|
SCENARIO("Mixed-color filament setup and painting round-trip through a .3mf", "[3mf][MixedFilament]") {
|
||||||
GIVEN("a painted model whose project config describes a mixed filament in the last slot") {
|
GIVEN("a painted model whose project config describes a mixed filament in the last slot") {
|
||||||
Model model;
|
Model model;
|
||||||
|
|||||||
@@ -101,10 +101,9 @@ TEST_CASE("check_mixed_filament_type_consistency flags mismatched component type
|
|||||||
|
|
||||||
TEST_CASE("a support-flagged component reads as its own filament type for the consistency check", "[FilamentMixer]")
|
TEST_CASE("a support-flagged component reads as its own filament type for the consistency check", "[FilamentMixer]")
|
||||||
{
|
{
|
||||||
// Sidebar::update_mixed_filament_list and Sidebar::has_broken_mixed_filament derive each
|
// The sidebar derives each component's type through DynamicPrintConfig::get_filament_type,
|
||||||
// component's type through DynamicPrintConfig::get_filament_type, which folds the
|
// which folds filament_is_support into the type, so toggling that flag alone flips the
|
||||||
// filament_is_support flag into the type — so toggling that flag alone changes the verdict
|
// verdict and the mixed filament list has to be refreshed on filament_is_support too.
|
||||||
// and Plater::on_config_change has to refresh the mixed list on filament_is_support too.
|
|
||||||
DynamicPrintConfig plain_pla;
|
DynamicPrintConfig plain_pla;
|
||||||
plain_pla.set_key_value("filament_type", new ConfigOptionStrings({"PLA"}));
|
plain_pla.set_key_value("filament_type", new ConfigOptionStrings({"PLA"}));
|
||||||
plain_pla.set_key_value("filament_is_support", new ConfigOptionBools({false}));
|
plain_pla.set_key_value("filament_is_support", new ConfigOptionBools({false}));
|
||||||
@@ -193,8 +192,8 @@ TEST_CASE("blend_color_multi weights components", "[FilamentMixer]")
|
|||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Mixing a color with itself stays close to that color") {
|
SECTION("Mixing a color with itself stays close to that color") {
|
||||||
// The mixer is a degree-4 polynomial fit of pigment behaviour, so a round trip through
|
// The mixer is a degree-4 polynomial fit of pigment behaviour, so mixing a color with
|
||||||
// it is near-identity rather than exact (the model documents a mean Delta-E around 2).
|
// itself lands near it rather than exactly on it; allow a small per-channel drift.
|
||||||
std::string mixed = blend_color_multi({"#123456", "#123456"}, {1, 1});
|
std::string mixed = blend_color_multi({"#123456", "#123456"}, {1, 1});
|
||||||
REQUIRE(mixed.size() == 7);
|
REQUIRE(mixed.size() == 7);
|
||||||
auto comp = [](const std::string &hex, int i) {
|
auto comp = [](const std::string &hex, int i) {
|
||||||
|
|||||||
@@ -614,12 +614,10 @@ TEST_CASE("set_num_filaments keeps mixed-color arrays in step with the filament
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A mix is described by 1-based indices into the project's filament list. Orca's per-printer
|
// A mix is described by 1-based indices into the project's filament list, which Orca rebuilds
|
||||||
// preset memory rebuilds that list from the selected printer's snapshot (filament_%02u /
|
// from the selected printer's snapshot (filament_%02u / filament_colors) at startup and on every
|
||||||
// filament_colors) at startup and on every printer selection, so the mixed arrays must be stored
|
// printer selection. Held anywhere but that same per-printer snapshot, the mixed arrays end up
|
||||||
// in the SAME per-printer snapshot: kept globally (as BambuStudio does — its filament list is a
|
// indexing a filament list they were never saved against.
|
||||||
// single global snapshot too) they end up indexing a list they were never saved against, and used
|
|
||||||
// to be reset on every printer selection instead, losing the mixes over an app restart.
|
|
||||||
TEST_CASE("Mixed-color filament metadata is snapshotted per printer, with its filament list", "[Preset][Bundle][FilamentMixer]")
|
TEST_CASE("Mixed-color filament metadata is snapshotted per printer, with its filament list", "[Preset][Bundle][FilamentMixer]")
|
||||||
{
|
{
|
||||||
PresetBundle bundle;
|
PresetBundle bundle;
|
||||||
@@ -674,10 +672,9 @@ TEST_CASE("A multi-point gradient curve survives the app-config snapshot", "[Pre
|
|||||||
}
|
}
|
||||||
|
|
||||||
// A multi-tool printer sizes the filament list from its nozzle count. Mixed-color slots are extra
|
// A multi-tool printer sizes the filament list from its nozzle count. Mixed-color slots are extra
|
||||||
// virtual filaments at the tail of that list with no nozzle of their own, so the sync has to add
|
// virtual filaments at the tail of that list with no nozzle of their own, so the count has to
|
||||||
// them on top. Sizing to the nozzle count alone truncates them — and because that sync runs right
|
// allow for them: sizing to the nozzle count alone drops the project's mixes and strips every
|
||||||
// after a project is loaded, it silently drops the project's mixes and then lets the filament-count
|
// painted facet above the new count.
|
||||||
// change strip every painted facet above the new count.
|
|
||||||
TEST_CASE("Sizing the filament list to a multi-tool nozzle count keeps mixed slots", "[Preset][Bundle][FilamentMixer]")
|
TEST_CASE("Sizing the filament list to a multi-tool nozzle count keeps mixed slots", "[Preset][Bundle][FilamentMixer]")
|
||||||
{
|
{
|
||||||
// The 5-slot layout of a 4-tool project carrying one mix of filaments 2 and 3.
|
// The 5-slot layout of a 4-tool project carrying one mix of filaments 2 and 3.
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ TEST_CASE("Extruder states above 17 are encoded in a second nibble", "[TriangleS
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Model.cpp writes these hex strings into the 3MF for colored mesh imports; the selector must
|
// Model.cpp writes these hex strings into the 3MF for colored mesh imports; the selector must
|
||||||
// decode exactly the states that table assigns to them.
|
// decode exactly the states CONST_FILAMENTS assigns to them.
|
||||||
TEST_CASE("Extruder states match the CONST_FILAMENTS hex encoding", "[TriangleSelector]")
|
TEST_CASE("Extruder states match the CONST_FILAMENTS hex encoding", "[TriangleSelector]")
|
||||||
{
|
{
|
||||||
struct Case { const char *hex; int state; };
|
struct Case { const char *hex; int state; };
|
||||||
|
|||||||
@@ -140,8 +140,8 @@ TEST_CASE("recompute_mixed_slot_colors honours the configured ratios and is idem
|
|||||||
// --- mixed_gradient_ramp / sample_gradient_ramp -----------------------------------------
|
// --- mixed_gradient_ramp / sample_gradient_ramp -----------------------------------------
|
||||||
//
|
//
|
||||||
// The ramp is what every mixed filament swatch is drawn from, so these pin the three things
|
// The ramp is what every mixed filament swatch is drawn from, so these pin the three things
|
||||||
// a plain two-endpoint fade got wrong: the reserved ratio band, the component order, and the
|
// a plain fade between two endpoint colours cannot express: the reserved ratio band, the
|
||||||
// custom curve.
|
// component order, and the custom curve.
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ TEST_CASE("mixed_gradient_ramp runs bottom to top and never reaches a pure compo
|
|||||||
REQUIRE(ramp.size() == 16);
|
REQUIRE(ramp.size() == 16);
|
||||||
|
|
||||||
// Neither end is the pure component colour - the slicer clamps the blend to
|
// Neither end is the pure component colour - the slicer clamps the blend to
|
||||||
// [kGradientMinRatio, kGradientMaxRatio], which is exactly what a two-endpoint fade missed.
|
// [kGradientMinRatio, kGradientMaxRatio], which a fade between the pure colours would ignore.
|
||||||
REQUIRE(ramp.front() != wxColour(255, 0, 0));
|
REQUIRE(ramp.front() != wxColour(255, 0, 0));
|
||||||
REQUIRE(ramp.back() != wxColour(0, 0, 255));
|
REQUIRE(ramp.back() != wxColour(0, 0, 255));
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ TEST_CASE("mixed_gradient_ramp follows the range's direction rather than the com
|
|||||||
REQUIRE(falling.size() == 16);
|
REQUIRE(falling.size() == 16);
|
||||||
|
|
||||||
// "0.1,0.9" starts blue-heavy at the bottom; "0.9,0.1" starts red-heavy. Reversing the
|
// "0.1,0.9" starts blue-heavy at the bottom; "0.9,0.1" starts red-heavy. Reversing the
|
||||||
// range must reverse the ramp, which HSV-sorted endpoint colours could not express.
|
// range must reverse the ramp, which endpoint colours ordered by HSV cannot express.
|
||||||
REQUIRE(int(rising.front().Blue()) > int(rising.front().Red()));
|
REQUIRE(int(rising.front().Blue()) > int(rising.front().Red()));
|
||||||
REQUIRE(int(falling.front().Red()) > int(falling.front().Blue()));
|
REQUIRE(int(falling.front().Red()) > int(falling.front().Blue()));
|
||||||
require_same_rgb(rising.front(), falling.back());
|
require_same_rgb(rising.front(), falling.back());
|
||||||
|
|||||||
Reference in New Issue
Block a user