Allow more than two colors per gradient
This commit is contained in:
@@ -534,6 +534,45 @@ static TextureMappingZone::LinearGradientAnchor linear_gradient_anchor_from_json
|
||||
return out;
|
||||
}
|
||||
|
||||
static nlohmann::json linear_gradient_stop_to_json(const TextureMappingZone::LinearGradientStop &stop)
|
||||
{
|
||||
nlohmann::json out;
|
||||
out["position"] = std::clamp(std::isfinite(stop.position) ? stop.position : 0.f, 0.f, 1.f);
|
||||
out["filament_id"] = stop.filament_id;
|
||||
return out;
|
||||
}
|
||||
|
||||
static TextureMappingZone::LinearGradientStop linear_gradient_stop_from_json(const nlohmann::json &value)
|
||||
{
|
||||
TextureMappingZone::LinearGradientStop out;
|
||||
if (!value.is_object())
|
||||
return out;
|
||||
const float position = value.value("position", 0.f);
|
||||
out.position = std::clamp(std::isfinite(position) ? position : 0.f, 0.f, 1.f);
|
||||
out.filament_id = value.value("filament_id", 1u);
|
||||
return out;
|
||||
}
|
||||
|
||||
static nlohmann::json linear_gradient_stops_to_json(const std::vector<TextureMappingZone::LinearGradientStop> &stops)
|
||||
{
|
||||
nlohmann::json out = nlohmann::json::array();
|
||||
for (const TextureMappingZone::LinearGradientStop &stop : stops)
|
||||
out.push_back(linear_gradient_stop_to_json(stop));
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::vector<TextureMappingZone::LinearGradientStop> linear_gradient_stops_from_json(const nlohmann::json &value)
|
||||
{
|
||||
std::vector<TextureMappingZone::LinearGradientStop> out;
|
||||
if (!value.is_array())
|
||||
return out;
|
||||
out.reserve(value.size());
|
||||
for (const nlohmann::json &item : value)
|
||||
if (item.is_object())
|
||||
out.emplace_back(linear_gradient_stop_from_json(item));
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::string surface_pattern_name(int surface_pattern)
|
||||
{
|
||||
if (surface_pattern == int(TextureMappingZone::Gradient2D))
|
||||
@@ -930,6 +969,17 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
|
||||
}
|
||||
return true;
|
||||
};
|
||||
auto stops_equal = [eps](const std::vector<TextureMappingZone::LinearGradientStop> &lhs,
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &rhs_values) {
|
||||
if (lhs.size() != rhs_values.size())
|
||||
return false;
|
||||
for (size_t i = 0; i < lhs.size(); ++i) {
|
||||
if (std::abs(lhs[i].position - rhs_values[i].position) > eps ||
|
||||
lhs[i].filament_id != rhs_values[i].filament_id)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
return stable_id == rhs.stable_id &&
|
||||
zone_id == rhs.zone_id &&
|
||||
@@ -990,7 +1040,8 @@ bool TextureMappingZone::operator==(const TextureMappingZone &rhs) const
|
||||
std::abs(linear_gradient_radius_mm - rhs.linear_gradient_radius_mm) <= eps &&
|
||||
linear_gradient_radius_percent == rhs.linear_gradient_radius_percent &&
|
||||
std::abs(linear_gradient_radius_pct - rhs.linear_gradient_radius_pct) <= eps &&
|
||||
show_linear_gradient_direction_arrow == rhs.show_linear_gradient_direction_arrow;
|
||||
show_linear_gradient_direction_arrow == rhs.show_linear_gradient_direction_arrow &&
|
||||
stops_equal(linear_gradient_stops, rhs.linear_gradient_stops);
|
||||
}
|
||||
|
||||
uint64_t TextureMappingManager::allocate_stable_id()
|
||||
@@ -1021,6 +1072,15 @@ void TextureMappingManager::refresh(const std::vector<std::string> &filament_col
|
||||
zone.stable_id = normalize_stable_id(zone.stable_id);
|
||||
if (zone.display_color.empty() || zone.display_color[0] != '#')
|
||||
zone.display_color = random_display_color(zone.stable_id);
|
||||
if (zone.is_linear_gradient()) {
|
||||
zone.linear_gradient_stops = normalized_linear_gradient_stops(zone, m_filament_colours.size());
|
||||
const std::vector<unsigned int> ids = linear_gradient_component_ids_from_stops(zone, m_filament_colours.size());
|
||||
zone.component_ids = encode_component_ids(ids);
|
||||
if (!zone.linear_gradient_stops.empty()) {
|
||||
zone.component_a = zone.linear_gradient_stops.front().filament_id;
|
||||
zone.component_b = zone.linear_gradient_stops.back().filament_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1044,6 +1104,8 @@ void TextureMappingManager::remove_physical_filament(unsigned int deleted_filame
|
||||
for (TextureMappingZone &zone : m_zones) {
|
||||
zone.component_a = remap_id(zone.component_a);
|
||||
zone.component_b = remap_id(zone.component_b);
|
||||
for (TextureMappingZone::LinearGradientStop &stop : zone.linear_gradient_stops)
|
||||
stop.filament_id = remap_id(stop.filament_id);
|
||||
|
||||
std::vector<unsigned int> ids = decode_component_ids(zone.component_ids, 9);
|
||||
for (unsigned int &id : ids)
|
||||
@@ -1063,13 +1125,18 @@ void TextureMappingManager::remove_physical_filament(unsigned int deleted_filame
|
||||
zone.component_a = ids[0];
|
||||
zone.component_b = ids[1];
|
||||
}
|
||||
if (zone.is_linear_gradient() && ids.size() > 2)
|
||||
ids.resize(2);
|
||||
if (zone.is_linear_gradient() && ids.size() >= 2) {
|
||||
if (zone.is_linear_gradient()) {
|
||||
zone.linear_gradient_stops = normalized_linear_gradient_stops(zone, new_physical_count);
|
||||
ids = linear_gradient_component_ids_from_stops(zone, new_physical_count);
|
||||
if (!zone.linear_gradient_stops.empty()) {
|
||||
zone.component_a = zone.linear_gradient_stops.front().filament_id;
|
||||
zone.component_b = zone.linear_gradient_stops.back().filament_id;
|
||||
}
|
||||
} else if (ids.size() >= 2) {
|
||||
zone.component_a = ids[0];
|
||||
zone.component_b = ids[1];
|
||||
}
|
||||
if (new_physical_count < 2)
|
||||
if (new_physical_count == 0 || (!zone.is_linear_gradient() && new_physical_count < 2))
|
||||
zone.enabled = false;
|
||||
zone.component_ids = encode_component_ids(ids);
|
||||
|
||||
@@ -1088,7 +1155,8 @@ TextureMappingZone *TextureMappingManager::add_zone(size_t num_physical,
|
||||
const std::vector<std::string> &filament_colours,
|
||||
int surface_pattern)
|
||||
{
|
||||
if (num_physical < 2)
|
||||
const bool linear_gradient = surface_pattern == int(TextureMappingZone::LinearGradient);
|
||||
if (num_physical == 0 || (!linear_gradient && num_physical < 2))
|
||||
return nullptr;
|
||||
|
||||
TextureMappingZone zone;
|
||||
@@ -1107,6 +1175,13 @@ TextureMappingZone *TextureMappingManager::add_zone(size_t num_physical,
|
||||
zone.component_ids = encode_component_ids(ids);
|
||||
zone.component_a = ids[0];
|
||||
zone.component_b = ids.size() > 1 ? ids[1] : ids[0];
|
||||
if (zone.is_linear_gradient()) {
|
||||
zone.linear_gradient_stops = {
|
||||
{0.f, zone.component_a},
|
||||
{1.f, zone.component_b}
|
||||
};
|
||||
zone.component_ids = encode_component_ids(linear_gradient_component_ids_from_stops(zone, num_physical));
|
||||
}
|
||||
zone.display_color = random_display_color(zone.stable_id);
|
||||
if (zone.is_image_texture())
|
||||
auto_adjust_texture_component_ids(zone, num_physical, filament_colours);
|
||||
@@ -1120,10 +1195,12 @@ bool TextureMappingManager::duplicate_zone(size_t zone_index,
|
||||
size_t num_physical,
|
||||
const std::vector<std::string> &filament_colours)
|
||||
{
|
||||
if (zone_index >= m_zones.size() || num_physical < 2)
|
||||
if (zone_index >= m_zones.size() || num_physical == 0)
|
||||
return false;
|
||||
|
||||
TextureMappingZone copy = m_zones[zone_index];
|
||||
if (!copy.is_linear_gradient() && num_physical < 2)
|
||||
return false;
|
||||
copy.stable_id = allocate_stable_id();
|
||||
copy.zone_id = allocate_zone_id(num_physical);
|
||||
if (copy.zone_id == 0)
|
||||
@@ -1192,20 +1269,23 @@ std::string TextureMappingManager::serialize_entries()
|
||||
zone.display_color = random_display_color(zone.stable_id);
|
||||
|
||||
std::vector<unsigned int> component_ids = decode_component_ids(zone.component_ids, 9);
|
||||
if (component_ids.size() < 2) {
|
||||
if (zone.is_linear_gradient()) {
|
||||
zone.linear_gradient_stops = normalized_linear_gradient_stops(zone, m_filament_colours.size());
|
||||
component_ids = linear_gradient_component_ids_from_stops(zone, m_filament_colours.size());
|
||||
if (!zone.linear_gradient_stops.empty()) {
|
||||
zone.component_a = zone.linear_gradient_stops.front().filament_id;
|
||||
zone.component_b = zone.linear_gradient_stops.back().filament_id;
|
||||
}
|
||||
zone.component_ids = encode_component_ids(component_ids);
|
||||
}
|
||||
if (!zone.is_linear_gradient() && component_ids.size() < 2) {
|
||||
component_ids = {zone.component_a, zone.component_b};
|
||||
component_ids.erase(std::remove_if(component_ids.begin(), component_ids.end(), [](unsigned int id) {
|
||||
return id == 0 || id > 9;
|
||||
}), component_ids.end());
|
||||
}
|
||||
if (zone.is_linear_gradient() && component_ids.size() > 2)
|
||||
component_ids.resize(2);
|
||||
unsigned int anchor_a = zone.component_a;
|
||||
unsigned int anchor_b = zone.component_b;
|
||||
if (zone.is_linear_gradient() && component_ids.size() >= 2) {
|
||||
anchor_a = component_ids[0];
|
||||
anchor_b = component_ids[1];
|
||||
}
|
||||
|
||||
const std::string normalized_weights = normalize_weights(zone.component_weights, component_ids.size());
|
||||
const std::string normalized_distances =
|
||||
@@ -1222,14 +1302,17 @@ std::string TextureMappingManager::serialize_entries()
|
||||
entry["zone_id"] = zone.zone_id;
|
||||
entry["enabled"] = zone.enabled;
|
||||
entry["surface_pattern"] = surface_pattern_name(zone.surface_pattern);
|
||||
entry["anchor_filaments"] = {anchor_a, anchor_b};
|
||||
entry["component_filaments"] = ids_to_json(component_ids);
|
||||
entry["component_weights_pct"] = weights_to_json(normalized_weights, component_ids.size());
|
||||
if (!zone.is_linear_gradient()) {
|
||||
entry["anchor_filaments"] = {anchor_a, anchor_b};
|
||||
entry["component_filaments"] = ids_to_json(component_ids);
|
||||
entry["component_weights_pct"] = weights_to_json(normalized_weights, component_ids.size());
|
||||
}
|
||||
entry["display_color"] = zone.display_color;
|
||||
if (zone.is_linear_gradient()) {
|
||||
nlohmann::json linear_gradient;
|
||||
linear_gradient["start"] = linear_gradient_anchor_to_json(zone.linear_gradient_start);
|
||||
linear_gradient["end"] = linear_gradient_anchor_to_json(zone.linear_gradient_end);
|
||||
linear_gradient["stops"] = linear_gradient_stops_to_json(zone.linear_gradient_stops);
|
||||
linear_gradient["mode"] = linear_gradient_mode_name(zone.linear_gradient_mode);
|
||||
linear_gradient["radius_mm"] = std::isfinite(zone.linear_gradient_radius_mm) ?
|
||||
std::max(0.f, zone.linear_gradient_radius_mm) :
|
||||
@@ -1322,7 +1405,7 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
refresh(filament_colours);
|
||||
|
||||
const size_t n = filament_colours.size();
|
||||
if (serialized.empty() || n < 2)
|
||||
if (serialized.empty() || n == 0)
|
||||
return;
|
||||
|
||||
nlohmann::json root;
|
||||
@@ -1354,22 +1437,32 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
continue;
|
||||
}
|
||||
|
||||
const int surface_pattern = surface_pattern_from_name(entry.value("surface_pattern", std::string("image_texture")));
|
||||
const bool linear_gradient = surface_pattern == int(TextureMappingZone::LinearGradient);
|
||||
std::vector<unsigned int> component_ids = ids_from_json(entry.value("component_filaments", nlohmann::json::array()), n);
|
||||
if (component_ids.size() < 2) {
|
||||
if (!linear_gradient && component_ids.size() < 2) {
|
||||
component_ids.clear();
|
||||
for (size_t i = 1; i <= std::min<size_t>(n, 9); ++i)
|
||||
component_ids.emplace_back(unsigned(i));
|
||||
}
|
||||
if (component_ids.size() < 2) {
|
||||
if (!linear_gradient && component_ids.size() < 2) {
|
||||
++skipped_rows;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> anchors = ids_from_json(entry.value("anchor_filaments", nlohmann::json::array()), n);
|
||||
if (anchors.size() < 2)
|
||||
if (anchors.size() < 2 && component_ids.size() >= 2)
|
||||
anchors = {component_ids[0], component_ids[1]};
|
||||
if (anchors[0] == anchors[1])
|
||||
else if (anchors.empty()) {
|
||||
const unsigned int anchor_a = component_ids.empty() ? 1u : component_ids.front();
|
||||
const unsigned int anchor_b = component_ids.size() >= 2 ? component_ids[1] : (n >= 2 && anchor_a == 1 ? 2u : anchor_a);
|
||||
anchors = {anchor_a, anchor_b};
|
||||
}
|
||||
while (anchors.size() < 2)
|
||||
anchors.emplace_back(anchors.front());
|
||||
if (!linear_gradient && anchors[0] == anchors[1] && n >= 2)
|
||||
anchors[1] = anchors[0] == 1 ? 2 : 1;
|
||||
if (linear_gradient && component_ids.empty())
|
||||
component_ids = {anchors[0], anchors[1]};
|
||||
|
||||
TextureMappingZone zone;
|
||||
zone.component_a = anchors[0];
|
||||
@@ -1378,13 +1471,7 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
zone.zone_id = entry.value("zone_id", entry.value("filament_id", 0u));
|
||||
zone.enabled = entry.value("enabled", true);
|
||||
zone.deleted = false;
|
||||
zone.surface_pattern = surface_pattern_from_name(entry.value("surface_pattern", std::string("image_texture")));
|
||||
if (zone.is_linear_gradient() && component_ids.size() > 2)
|
||||
component_ids.resize(2);
|
||||
if (zone.is_linear_gradient() && component_ids.size() >= 2) {
|
||||
zone.component_a = component_ids[0];
|
||||
zone.component_b = component_ids[1];
|
||||
}
|
||||
zone.surface_pattern = surface_pattern;
|
||||
zone.component_ids = encode_component_ids(component_ids);
|
||||
zone.component_weights =
|
||||
weights_from_json(entry.value("component_weights_pct", nlohmann::json::array()), component_ids.size());
|
||||
@@ -1395,6 +1482,14 @@ void TextureMappingManager::load_entries(const std::string &serialized,
|
||||
const nlohmann::json linear_gradient = entry.value("linear_gradient", nlohmann::json::object());
|
||||
zone.linear_gradient_start = linear_gradient_anchor_from_json(linear_gradient.value("start", nlohmann::json::object()));
|
||||
zone.linear_gradient_end = linear_gradient_anchor_from_json(linear_gradient.value("end", nlohmann::json::object()));
|
||||
zone.linear_gradient_stops = linear_gradient_stops_from_json(linear_gradient.value("stops", nlohmann::json::array()));
|
||||
zone.linear_gradient_stops = normalized_linear_gradient_stops(zone, n);
|
||||
component_ids = linear_gradient_component_ids_from_stops(zone, n);
|
||||
if (!zone.linear_gradient_stops.empty()) {
|
||||
zone.component_a = zone.linear_gradient_stops.front().filament_id;
|
||||
zone.component_b = zone.linear_gradient_stops.back().filament_id;
|
||||
}
|
||||
zone.component_ids = encode_component_ids(component_ids);
|
||||
zone.linear_gradient_mode = linear_gradient_mode_from_name(linear_gradient.value("mode", std::string("linear")));
|
||||
const float radius_mm = linear_gradient.value("radius_mm", TextureMappingZone::DefaultLinearGradientRadiusMm);
|
||||
zone.linear_gradient_radius_mm = std::isfinite(radius_mm) ? std::max(0.f, radius_mm) : TextureMappingZone::DefaultLinearGradientRadiusMm;
|
||||
@@ -1680,12 +1775,127 @@ bool TextureMappingManager::component_count_mismatch(const TextureMappingZone &z
|
||||
return expected != 0 && selected_component_ids(zone, num_physical).size() != expected;
|
||||
}
|
||||
|
||||
std::vector<TextureMappingZone::LinearGradientStop> TextureMappingManager::normalized_linear_gradient_stops(const TextureMappingZone &zone,
|
||||
size_t num_physical)
|
||||
{
|
||||
const unsigned int max_id = unsigned(std::min<size_t>(num_physical, 9));
|
||||
std::vector<TextureMappingZone::LinearGradientStop> stops;
|
||||
if (max_id == 0)
|
||||
return stops;
|
||||
|
||||
stops.reserve(zone.linear_gradient_stops.size());
|
||||
for (TextureMappingZone::LinearGradientStop stop : zone.linear_gradient_stops) {
|
||||
if (stop.filament_id < 1 || stop.filament_id > max_id)
|
||||
continue;
|
||||
stop.position = std::clamp(std::isfinite(stop.position) ? stop.position : 0.f, 0.f, 1.f);
|
||||
stops.emplace_back(stop);
|
||||
}
|
||||
|
||||
if (stops.size() < 2) {
|
||||
std::vector<unsigned int> ids = decode_component_ids(zone.component_ids, num_physical);
|
||||
if (ids.size() < 2) {
|
||||
ids.clear();
|
||||
if (zone.component_a >= 1 && zone.component_a <= max_id)
|
||||
ids.emplace_back(zone.component_a);
|
||||
if (zone.component_b >= 1 && zone.component_b <= max_id)
|
||||
ids.emplace_back(zone.component_b);
|
||||
}
|
||||
if (ids.empty())
|
||||
ids.emplace_back(1);
|
||||
while (ids.size() < 2)
|
||||
ids.emplace_back(ids.front());
|
||||
stops = {
|
||||
{0.f, std::clamp(ids[0], 1u, max_id)},
|
||||
{1.f, std::clamp(ids[1], 1u, max_id)}
|
||||
};
|
||||
}
|
||||
|
||||
std::stable_sort(stops.begin(), stops.end(), [](const auto &lhs, const auto &rhs) {
|
||||
return lhs.position < rhs.position;
|
||||
});
|
||||
return stops;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> TextureMappingManager::linear_gradient_component_ids_from_stops(const TextureMappingZone &zone,
|
||||
size_t num_physical)
|
||||
{
|
||||
std::vector<unsigned int> ids;
|
||||
bool seen[10] = { false };
|
||||
for (const TextureMappingZone::LinearGradientStop &stop : normalized_linear_gradient_stops(zone, num_physical)) {
|
||||
const unsigned int id = stop.filament_id;
|
||||
if (id == 0 || id > num_physical || id > 9 || seen[id])
|
||||
continue;
|
||||
seen[id] = true;
|
||||
ids.emplace_back(id);
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
std::vector<float> TextureMappingManager::linear_gradient_compact_weights(float t,
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &stops,
|
||||
const std::vector<unsigned int> &component_ids)
|
||||
{
|
||||
std::vector<float> weights(component_ids.size(), 0.f);
|
||||
if (stops.empty() || component_ids.empty())
|
||||
return weights;
|
||||
|
||||
auto add_weight = [&weights, &component_ids](unsigned int filament_id, float weight) {
|
||||
if (weight <= 0.f)
|
||||
return;
|
||||
for (size_t idx = 0; idx < component_ids.size(); ++idx) {
|
||||
if (component_ids[idx] == filament_id) {
|
||||
weights[idx] = std::max(weights[idx], std::clamp(weight, 0.f, 1.f));
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const float clamped_t = std::clamp(std::isfinite(t) ? t : 0.f, 0.f, 1.f);
|
||||
if (clamped_t <= stops.front().position) {
|
||||
add_weight(stops.front().filament_id, 1.f);
|
||||
return weights;
|
||||
}
|
||||
if (clamped_t >= stops.back().position) {
|
||||
add_weight(stops.back().filament_id, 1.f);
|
||||
return weights;
|
||||
}
|
||||
|
||||
size_t right = 1;
|
||||
while (right < stops.size() && clamped_t > stops[right].position)
|
||||
++right;
|
||||
if (right >= stops.size()) {
|
||||
add_weight(stops.back().filament_id, 1.f);
|
||||
return weights;
|
||||
}
|
||||
|
||||
const TextureMappingZone::LinearGradientStop &lhs = stops[right - 1];
|
||||
const TextureMappingZone::LinearGradientStop &rhs = stops[right];
|
||||
const float denom = rhs.position - lhs.position;
|
||||
if (lhs.filament_id == rhs.filament_id || denom <= 1e-6f) {
|
||||
add_weight(rhs.filament_id, 1.f);
|
||||
return weights;
|
||||
}
|
||||
|
||||
const float local_t = std::clamp((clamped_t - lhs.position) / denom, 0.f, 1.f);
|
||||
float lhs_weight = 1.f - local_t;
|
||||
float rhs_weight = local_t;
|
||||
const float max_weight = std::max(lhs_weight, rhs_weight);
|
||||
if (max_weight > 1e-6f) {
|
||||
lhs_weight /= max_weight;
|
||||
rhs_weight /= max_weight;
|
||||
}
|
||||
add_weight(lhs.filament_id, lhs_weight);
|
||||
add_weight(rhs.filament_id, rhs_weight);
|
||||
return weights;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> TextureMappingManager::selected_component_ids(const TextureMappingZone &zone, size_t num_physical)
|
||||
{
|
||||
if (zone.is_linear_gradient())
|
||||
return linear_gradient_component_ids_from_stops(zone, num_physical);
|
||||
|
||||
std::vector<unsigned int> ids = decode_component_ids(zone.component_ids, num_physical);
|
||||
if (!ids.empty()) {
|
||||
if (zone.is_linear_gradient() && ids.size() > 2)
|
||||
ids.resize(2);
|
||||
return ids;
|
||||
}
|
||||
|
||||
@@ -1693,8 +1903,6 @@ std::vector<unsigned int> TextureMappingManager::selected_component_ids(const Te
|
||||
ids.emplace_back(zone.component_a);
|
||||
if (zone.component_b >= 1 && zone.component_b <= num_physical && zone.component_b != zone.component_a)
|
||||
ids.emplace_back(zone.component_b);
|
||||
if (zone.is_linear_gradient() && ids.size() > 2)
|
||||
ids.resize(2);
|
||||
return ids;
|
||||
}
|
||||
|
||||
|
||||
@@ -167,6 +167,11 @@ struct TextureMappingZone
|
||||
std::array<float, 3> global_point { { 0.f, 0.f, 0.f } };
|
||||
};
|
||||
|
||||
struct LinearGradientStop {
|
||||
float position = 0.f;
|
||||
unsigned int filament_id = 1;
|
||||
};
|
||||
|
||||
uint64_t stable_id = 0;
|
||||
unsigned int zone_id = 0;
|
||||
bool enabled = true;
|
||||
@@ -229,6 +234,7 @@ struct TextureMappingZone
|
||||
bool linear_gradient_radius_percent = DefaultLinearGradientRadiusPercent;
|
||||
float linear_gradient_radius_pct = DefaultLinearGradientRadiusPct;
|
||||
bool show_linear_gradient_direction_arrow = true;
|
||||
std::vector<LinearGradientStop> linear_gradient_stops;
|
||||
|
||||
bool is_image_texture() const { return surface_pattern == int(ImageTexture); }
|
||||
bool is_2d_gradient() const { return surface_pattern == int(Gradient2D); }
|
||||
@@ -287,6 +293,7 @@ struct TextureMappingZone
|
||||
linear_gradient_radius_mm = DefaultLinearGradientRadiusMm;
|
||||
linear_gradient_radius_percent = DefaultLinearGradientRadiusPercent;
|
||||
linear_gradient_radius_pct = DefaultLinearGradientRadiusPct;
|
||||
linear_gradient_stops.clear();
|
||||
filament_strengths_pct.clear();
|
||||
filament_minimum_offsets_pct.clear();
|
||||
filament_transmission_distances_mm.clear();
|
||||
@@ -432,6 +439,13 @@ public:
|
||||
static bool auto_adjust_texture_component_ids(TextureMappingZone &zone,
|
||||
size_t num_physical,
|
||||
const std::vector<std::string> &filament_colours);
|
||||
static std::vector<TextureMappingZone::LinearGradientStop> normalized_linear_gradient_stops(const TextureMappingZone &zone,
|
||||
size_t num_physical);
|
||||
static std::vector<unsigned int> linear_gradient_component_ids_from_stops(const TextureMappingZone &zone,
|
||||
size_t num_physical);
|
||||
static std::vector<float> linear_gradient_compact_weights(float t,
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &stops,
|
||||
const std::vector<unsigned int> &component_ids);
|
||||
static std::vector<TextureMappingColorMatch> texture_component_color_matches(const TextureMappingZone &zone,
|
||||
size_t num_physical,
|
||||
const std::vector<std::string> &filament_colours);
|
||||
|
||||
@@ -2675,6 +2675,9 @@ std::optional<std::array<float, 3>> sample_weight_field_rgb(const TextureMapping
|
||||
|
||||
std::vector<unsigned int> decode_texture_mapping_offset_component_ids(const TextureMappingZone &zone, size_t num_physical)
|
||||
{
|
||||
if (zone.is_linear_gradient())
|
||||
return TextureMappingManager::linear_gradient_component_ids_from_stops(zone, num_physical);
|
||||
|
||||
std::vector<unsigned int> out;
|
||||
for (const char c : zone.component_ids) {
|
||||
if (c < '1' || c > '9')
|
||||
@@ -2771,13 +2774,6 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
if (!effective_component_ids.empty())
|
||||
component_ids = effective_component_ids;
|
||||
}
|
||||
if (linear_gradient_mode && component_ids.size() > 2)
|
||||
component_ids.resize(2);
|
||||
if (linear_gradient_mode && component_ids.size() < 2) {
|
||||
component_ids.clear();
|
||||
for (size_t i = 1; i <= std::min<size_t>(num_physical, 2); ++i)
|
||||
component_ids.emplace_back(unsigned(i));
|
||||
}
|
||||
if (component_ids.empty())
|
||||
return std::nullopt;
|
||||
|
||||
@@ -3046,6 +3042,8 @@ std::optional<TextureMappingOffsetContext> build_texture_mapping_offset_context_
|
||||
context.active_component_id = active_component_id;
|
||||
context.active_component_idx = active_component_idx;
|
||||
context.component_ids = std::move(component_ids);
|
||||
if (linear_gradient_mode)
|
||||
context.linear_gradient_stops = TextureMappingManager::normalized_linear_gradient_stops(zone, num_physical);
|
||||
context.component_distances_mm = std::move(distances_mm);
|
||||
context.rotated_angles = std::move(rotated_angles);
|
||||
context.weight_field = std::move(weight_field);
|
||||
@@ -3129,12 +3127,11 @@ float texture_mapping_offset_surface_inset_mm(const TextureMappingOffsetContext
|
||||
t = clamp01f((sample - context.linear_gradient_start_mm).dot(gradient_vec) / denom);
|
||||
}
|
||||
if (context.linear_gradient_radial_mode || (context.linear_gradient_end_mm - context.linear_gradient_start_mm).squaredNorm() > 1e-8f) {
|
||||
float desired_strength = context.active_component_idx == 0 ? 1.f - t :
|
||||
context.active_component_idx == 1 ? t :
|
||||
0.f;
|
||||
const float max_strength = std::max(1.f - t, t);
|
||||
if (max_strength > EPSILON)
|
||||
desired_strength = clamp01f(desired_strength / max_strength);
|
||||
const std::vector<float> weights =
|
||||
TextureMappingManager::linear_gradient_compact_weights(t, context.linear_gradient_stops, context.component_ids);
|
||||
const float desired_strength = context.active_component_idx < weights.size() ?
|
||||
clamp01f(weights[context.active_component_idx]) :
|
||||
0.f;
|
||||
inset_strength = std::clamp(1.f - desired_strength, 0.f, 1.f);
|
||||
} else {
|
||||
inset_strength = 0.f;
|
||||
|
||||
@@ -66,6 +66,7 @@ struct TextureMappingOffsetContext {
|
||||
Vec3f linear_gradient_end_mm { Vec3f::Zero() };
|
||||
bool linear_gradient_radial_mode { false };
|
||||
float linear_gradient_radius_mm { 0.f };
|
||||
std::vector<TextureMappingZone::LinearGradientStop> linear_gradient_stops;
|
||||
unsigned int active_component_id { 0 };
|
||||
size_t active_component_idx { size_t(-1) };
|
||||
std::vector<unsigned int> component_ids;
|
||||
|
||||
@@ -364,10 +364,8 @@ std::vector<unsigned int> linear_gradient_component_ids_for_arrow(const TextureM
|
||||
return id == 0 || id > num_physical;
|
||||
}), ids.end());
|
||||
ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
|
||||
if (ids.size() > 2)
|
||||
ids.resize(2);
|
||||
if (ids.size() < 2 && num_physical >= 2)
|
||||
ids = {1, 2};
|
||||
if (ids.empty() && num_physical >= 1)
|
||||
ids = {1};
|
||||
return ids;
|
||||
}
|
||||
|
||||
@@ -381,16 +379,24 @@ std::array<float, 3> linear_gradient_filament_color(unsigned int filament_id, co
|
||||
return { 0.5f, 0.5f, 0.5f };
|
||||
}
|
||||
|
||||
ColorRGBA linear_gradient_arrow_color(const std::array<float, 3> &start_color,
|
||||
const std::array<float, 3> &end_color,
|
||||
ColorRGBA linear_gradient_arrow_color(const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &stops,
|
||||
const std::vector<unsigned int> &component_ids,
|
||||
float t)
|
||||
{
|
||||
std::vector<std::array<float, 3>> colors { start_color, end_color };
|
||||
std::vector<float> weights { std::clamp(1.f - t, 0.f, 1.f), std::clamp(t, 0.f, 1.f) };
|
||||
const std::array<float, 3> mixed = mix_color_solver_components(colors, weights, ColorSolverMixModel::PigmentPainter);
|
||||
const std::vector<float> weights = TextureMappingManager::linear_gradient_compact_weights(t, stops, component_ids);
|
||||
const std::array<float, 3> mixed = mix_color_solver_components(component_colors, weights, ColorSolverMixModel::PigmentPainter);
|
||||
return { std::clamp(mixed[0], 0.f, 1.f), std::clamp(mixed[1], 0.f, 1.f), std::clamp(mixed[2], 0.f, 1.f), 1.f };
|
||||
}
|
||||
|
||||
float linear_gradient_arrow_t(const Vec3f &point,
|
||||
const Vec3f &arrow_start,
|
||||
const Vec3f &axis,
|
||||
float arrow_length)
|
||||
{
|
||||
return std::clamp((point - arrow_start).dot(axis) / std::max(0.0001f, arrow_length), 0.f, 1.f);
|
||||
}
|
||||
|
||||
struct LinearGradientArrowUsage {
|
||||
bool any { false };
|
||||
Vec3f default_start { Vec3f::Zero() };
|
||||
@@ -493,39 +499,43 @@ void append_linear_gradient_cylinder(GUI::GLModel::Geometry &geometry,
|
||||
const Vec3f &u,
|
||||
const Vec3f &v,
|
||||
float radius,
|
||||
const std::array<float, 3> &start_color,
|
||||
const std::array<float, 3> &end_color,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &stops,
|
||||
const std::vector<unsigned int> &component_ids,
|
||||
bool black)
|
||||
{
|
||||
constexpr int sectors = 32;
|
||||
constexpr int axial_steps = 72;
|
||||
const ColorRGBA black_color = ColorRGBA::BLACK();
|
||||
const float safe_arrow_length = std::max(0.0001f, arrow_length);
|
||||
const float center_t = std::clamp((start - arrow_start).dot(axis) / safe_arrow_length, 0.f, 1.f);
|
||||
std::vector<std::vector<unsigned int>> ring_ids(size_t(axial_steps + 1), std::vector<unsigned int>(size_t(sectors + 1), 0));
|
||||
for (int step = 0; step <= axial_steps; ++step) {
|
||||
const float step_t = float(step) / float(axial_steps);
|
||||
const Vec3f center = start + (end - start) * step_t;
|
||||
const float arrow_t = linear_gradient_arrow_t(center, arrow_start, axis, arrow_length);
|
||||
const ColorRGBA color = black ? black_color : linear_gradient_arrow_color(component_colors, stops, component_ids, arrow_t);
|
||||
for (int sector = 0; sector <= sectors; ++sector) {
|
||||
const float a = 2.f * float(PI) * float(sector) / float(sectors);
|
||||
const Vec3f radial = std::cos(a) * u + std::sin(a) * v;
|
||||
ring_ids[size_t(step)][size_t(sector)] =
|
||||
linear_gradient_add_vertex(geometry, center + radius * radial, radial, color);
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned int start_center =
|
||||
linear_gradient_add_vertex(geometry,
|
||||
start,
|
||||
-axis,
|
||||
black ? black_color : linear_gradient_arrow_color(start_color, end_color, center_t));
|
||||
black ? black_color : linear_gradient_arrow_color(component_colors, stops, component_ids, linear_gradient_arrow_t(start, arrow_start, axis, arrow_length)));
|
||||
for (int i = 0; i < sectors; ++i) {
|
||||
const float a0 = 2.f * float(PI) * float(i) / float(sectors);
|
||||
const float a1 = 2.f * float(PI) * float(i + 1) / float(sectors);
|
||||
const Vec3f r0 = std::cos(a0) * u + std::sin(a0) * v;
|
||||
const Vec3f r1 = std::cos(a1) * u + std::sin(a1) * v;
|
||||
const Vec3f p0 = start + radius * r0;
|
||||
const Vec3f p1 = start + radius * r1;
|
||||
const Vec3f p2 = end + radius * r0;
|
||||
const Vec3f p3 = end + radius * r1;
|
||||
const float t0 = std::clamp((p0 - arrow_start).dot(axis) / safe_arrow_length, 0.f, 1.f);
|
||||
const float t1 = std::clamp((p2 - arrow_start).dot(axis) / safe_arrow_length, 0.f, 1.f);
|
||||
const ColorRGBA c0 = black ? black_color : linear_gradient_arrow_color(start_color, end_color, t0);
|
||||
const ColorRGBA c1 = black ? black_color : linear_gradient_arrow_color(start_color, end_color, t1);
|
||||
const unsigned int i0 = linear_gradient_add_vertex(geometry, p0, r0, c0);
|
||||
const unsigned int i1 = linear_gradient_add_vertex(geometry, p1, r1, c0);
|
||||
const unsigned int i2 = linear_gradient_add_vertex(geometry, p2, r0, c1);
|
||||
const unsigned int i3 = linear_gradient_add_vertex(geometry, p3, r1, c1);
|
||||
geometry.add_triangle(i0, i2, i1);
|
||||
geometry.add_triangle(i1, i2, i3);
|
||||
geometry.add_triangle(start_center, i1, i0);
|
||||
geometry.add_triangle(start_center, ring_ids[0][size_t(i + 1)], ring_ids[0][size_t(i)]);
|
||||
for (int step = 0; step < axial_steps; ++step) {
|
||||
const unsigned int i0 = ring_ids[size_t(step)][size_t(i)];
|
||||
const unsigned int i1 = ring_ids[size_t(step)][size_t(i + 1)];
|
||||
const unsigned int i2 = ring_ids[size_t(step + 1)][size_t(i)];
|
||||
const unsigned int i3 = ring_ids[size_t(step + 1)][size_t(i + 1)];
|
||||
geometry.add_triangle(i0, i2, i1);
|
||||
geometry.add_triangle(i1, i2, i3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,30 +548,44 @@ void append_linear_gradient_cone(GUI::GLModel::Geometry &geometry,
|
||||
const Vec3f &u,
|
||||
const Vec3f &v,
|
||||
float radius,
|
||||
const std::array<float, 3> &start_color,
|
||||
const std::array<float, 3> &end_color,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &stops,
|
||||
const std::vector<unsigned int> &component_ids,
|
||||
bool black)
|
||||
{
|
||||
constexpr int sectors = 32;
|
||||
constexpr int axial_steps = 24;
|
||||
const ColorRGBA black_color = ColorRGBA::BLACK();
|
||||
const float safe_arrow_length = std::max(0.0001f, arrow_length);
|
||||
const float tip_t = std::clamp((tip - arrow_start).dot(axis) / safe_arrow_length, 0.f, 1.f);
|
||||
const ColorRGBA tip_color = black ? black_color : linear_gradient_arrow_color(start_color, end_color, tip_t);
|
||||
const ColorRGBA tip_color = black ? black_color : linear_gradient_arrow_color(component_colors, stops, component_ids, linear_gradient_arrow_t(tip, arrow_start, axis, arrow_length));
|
||||
std::vector<std::vector<unsigned int>> ring_ids(size_t(axial_steps), std::vector<unsigned int>(size_t(sectors + 1), 0));
|
||||
const Vec3f cone_axis = tip - base;
|
||||
for (int step = 0; step < axial_steps; ++step) {
|
||||
const float step_t = float(step) / float(axial_steps);
|
||||
const Vec3f center = base + cone_axis * step_t;
|
||||
const float ring_radius = radius * (1.f - step_t);
|
||||
const ColorRGBA color = black ? black_color : linear_gradient_arrow_color(component_colors, stops, component_ids, linear_gradient_arrow_t(center, arrow_start, axis, arrow_length));
|
||||
for (int sector = 0; sector <= sectors; ++sector) {
|
||||
const float a = 2.f * float(PI) * float(sector) / float(sectors);
|
||||
const Vec3f radial = std::cos(a) * u + std::sin(a) * v;
|
||||
const Vec3f normal = (radial + axis * 0.35f).normalized();
|
||||
ring_ids[size_t(step)][size_t(sector)] =
|
||||
linear_gradient_add_vertex(geometry, center + ring_radius * radial, normal, color);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < sectors; ++i) {
|
||||
const float a0 = 2.f * float(PI) * float(i) / float(sectors);
|
||||
const float a1 = 2.f * float(PI) * float(i + 1) / float(sectors);
|
||||
const Vec3f r0 = std::cos(a0) * u + std::sin(a0) * v;
|
||||
const Vec3f r1 = std::cos(a1) * u + std::sin(a1) * v;
|
||||
const Vec3f p0 = base + radius * r0;
|
||||
const Vec3f p1 = base + radius * r1;
|
||||
const float base_t = std::clamp((base - arrow_start).dot(axis) / safe_arrow_length, 0.f, 1.f);
|
||||
const ColorRGBA base_color = black ? black_color : linear_gradient_arrow_color(start_color, end_color, base_t);
|
||||
const Vec3f n0 = (r0 + axis * 0.35f).normalized();
|
||||
const Vec3f n1 = (r1 + axis * 0.35f).normalized();
|
||||
const unsigned int i0 = linear_gradient_add_vertex(geometry, p0, n0, base_color);
|
||||
const unsigned int i1 = linear_gradient_add_vertex(geometry, p1, n1, base_color);
|
||||
const unsigned int i2 = linear_gradient_add_vertex(geometry, tip, axis, tip_color);
|
||||
geometry.add_triangle(i0, i2, i1);
|
||||
for (int step = 0; step + 1 < axial_steps; ++step) {
|
||||
const unsigned int i0 = ring_ids[size_t(step)][size_t(i)];
|
||||
const unsigned int i1 = ring_ids[size_t(step)][size_t(i + 1)];
|
||||
const unsigned int i2 = ring_ids[size_t(step + 1)][size_t(i)];
|
||||
const unsigned int i3 = ring_ids[size_t(step + 1)][size_t(i + 1)];
|
||||
geometry.add_triangle(i0, i2, i1);
|
||||
geometry.add_triangle(i1, i2, i3);
|
||||
}
|
||||
const unsigned int i0 = ring_ids[size_t(axial_steps - 1)][size_t(i)];
|
||||
const unsigned int i1 = ring_ids[size_t(axial_steps - 1)][size_t(i + 1)];
|
||||
const unsigned int tip_idx = linear_gradient_add_vertex(geometry, tip, axis, tip_color);
|
||||
geometry.add_triangle(i0, tip_idx, i1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,8 +685,9 @@ void append_linear_gradient_arrow(GUI::GLModel::Geometry &geometry,
|
||||
float radius,
|
||||
float head_radius,
|
||||
float head_length,
|
||||
const std::array<float, 3> &start_color,
|
||||
const std::array<float, 3> &end_color,
|
||||
const std::vector<std::array<float, 3>> &component_colors,
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &stops,
|
||||
const std::vector<unsigned int> &component_ids,
|
||||
bool black)
|
||||
{
|
||||
const Vec3f delta = end - start;
|
||||
@@ -676,8 +701,8 @@ void append_linear_gradient_arrow(GUI::GLModel::Geometry &geometry,
|
||||
float clamped_head_length = std::min(head_length, length * 0.75f);
|
||||
clamped_head_length = std::max(clamped_head_length, std::min(radius * 2.f, length * 0.5f));
|
||||
const Vec3f shaft_end = start + axis * std::max(radius, length - clamped_head_length);
|
||||
append_linear_gradient_cylinder(geometry, start, shaft_end, start, length, axis, u, v, radius, start_color, end_color, black);
|
||||
append_linear_gradient_cone(geometry, shaft_end, end, start, length, axis, u, v, head_radius, start_color, end_color, black);
|
||||
append_linear_gradient_cylinder(geometry, start, shaft_end, start, length, axis, u, v, radius, component_colors, stops, component_ids, black);
|
||||
append_linear_gradient_cone(geometry, shaft_end, end, start, length, axis, u, v, head_radius, component_colors, stops, component_ids, black);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -3173,8 +3198,14 @@ void GLVolumeCollection::render_linear_gradient_direction_arrows(const Transform
|
||||
continue;
|
||||
|
||||
const std::vector<unsigned int> component_ids = linear_gradient_component_ids_for_arrow(zone, num_physical);
|
||||
if (component_ids.size() < 2)
|
||||
if (component_ids.empty())
|
||||
continue;
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> gradient_stops =
|
||||
TextureMappingManager::normalized_linear_gradient_stops(zone, num_physical);
|
||||
std::vector<std::array<float, 3>> component_colors;
|
||||
component_colors.reserve(component_ids.size());
|
||||
for (const unsigned int component_id : component_ids)
|
||||
component_colors.emplace_back(linear_gradient_filament_color(component_id, filament_colors));
|
||||
|
||||
const LinearGradientArrowUsage usage = linear_gradient_arrow_usage(volumes, zone.zone_id);
|
||||
const std::optional<Vec3f> start_anchor = linear_gradient_anchor_global_point(volumes, zone.linear_gradient_start);
|
||||
@@ -3219,8 +3250,6 @@ void GLVolumeCollection::render_linear_gradient_direction_arrows(const Transform
|
||||
delta = end - start;
|
||||
}
|
||||
|
||||
const std::array<float, 3> start_color = linear_gradient_filament_color(component_ids[0], filament_colors);
|
||||
const std::array<float, 3> end_color = linear_gradient_filament_color(component_ids[1], filament_colors);
|
||||
const float shaft_radius = std::clamp(length * 0.018f, 0.35f, 2.2f);
|
||||
const float head_length = std::min(length * 0.24f, std::max(shaft_radius * 4.f, length * 0.12f));
|
||||
const float head_radius = shaft_radius * 3.1f;
|
||||
@@ -3230,8 +3259,9 @@ void GLVolumeCollection::render_linear_gradient_direction_arrows(const Transform
|
||||
shaft_radius * 1.55f,
|
||||
head_radius * 1.28f,
|
||||
head_length,
|
||||
start_color,
|
||||
end_color,
|
||||
component_colors,
|
||||
gradient_stops,
|
||||
component_ids,
|
||||
true);
|
||||
append_linear_gradient_arrow(color_geometry,
|
||||
start,
|
||||
@@ -3239,8 +3269,9 @@ void GLVolumeCollection::render_linear_gradient_direction_arrows(const Transform
|
||||
shaft_radius,
|
||||
head_radius,
|
||||
head_length,
|
||||
start_color,
|
||||
end_color,
|
||||
component_colors,
|
||||
gradient_stops,
|
||||
component_ids,
|
||||
false);
|
||||
|
||||
const float sphere_radius = shaft_radius * 2.45f;
|
||||
|
||||
@@ -124,6 +124,7 @@ struct SurfaceGradientPreviewSettings
|
||||
Vec3f linear_start = Vec3f::Zero();
|
||||
Vec3f linear_end = Vec3f::UnitZ();
|
||||
float linear_radius_mm = 1.f;
|
||||
std::vector<TextureMappingZone::LinearGradientStop> linear_gradient_stops;
|
||||
std::vector<std::array<float, 3>> linear_gradient_lut_colors;
|
||||
};
|
||||
|
||||
@@ -397,27 +398,6 @@ std::array<float, 3> decode_color(const std::string &color)
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<float> compact_linear_gradient_weights(float t, size_t component_count)
|
||||
{
|
||||
std::vector<float> weights(component_count, 0.f);
|
||||
if (component_count == 0)
|
||||
return weights;
|
||||
if (component_count == 1) {
|
||||
weights[0] = 1.f;
|
||||
return weights;
|
||||
}
|
||||
|
||||
weights[0] = 1.f - std::clamp(t, 0.f, 1.f);
|
||||
weights[1] = std::clamp(t, 0.f, 1.f);
|
||||
float max_weight = 0.f;
|
||||
for (const float weight : weights)
|
||||
max_weight = std::max(max_weight, std::clamp(weight, 0.f, 1.f));
|
||||
if (max_weight > k_epsilon)
|
||||
for (float &weight : weights)
|
||||
weight = std::clamp(weight / max_weight, 0.f, 1.f);
|
||||
return weights;
|
||||
}
|
||||
|
||||
ColorRGBA blend_component_colors(const std::vector<std::array<float, 3>> &colors, const std::vector<float> &weights)
|
||||
{
|
||||
if (colors.empty() || weights.empty())
|
||||
@@ -1065,6 +1045,8 @@ bool texture_preview_settings_invalid_for_filament(unsigned int filament_id, siz
|
||||
return false;
|
||||
if (is_image_zone(*zone))
|
||||
return TextureMappingManager::component_count_mismatch(*zone, num_physical);
|
||||
if (is_gradient_zone(*zone) && zone->is_linear_gradient())
|
||||
return TextureMappingManager::selected_component_ids(*zone, num_physical).empty();
|
||||
if (is_gradient_zone(*zone))
|
||||
return TextureMappingManager::selected_component_ids(*zone, num_physical).size() < 2;
|
||||
return false;
|
||||
@@ -4112,6 +4094,9 @@ bool build_simulated_image_texture_halftone_preview_model_for_state(
|
||||
|
||||
std::vector<unsigned int> decode_surface_gradient_component_ids(const TextureMappingZone &zone, size_t num_physical)
|
||||
{
|
||||
if (zone.is_linear_gradient())
|
||||
return TextureMappingManager::linear_gradient_component_ids_from_stops(zone, num_physical);
|
||||
|
||||
std::vector<unsigned int> ids;
|
||||
bool seen[10] = { false };
|
||||
for (const char c : zone.component_ids) {
|
||||
@@ -4357,10 +4342,9 @@ std::optional<SurfaceGradientPreviewSettings> surface_gradient_preview_settings_
|
||||
const std::vector<std::string> colors = physical_filament_colors_for_texture_preview(num_physical);
|
||||
SurfaceGradientPreviewSettings settings;
|
||||
settings.component_ids = decode_surface_gradient_component_ids(zone, num_physical);
|
||||
if (zone.is_linear_gradient() && settings.component_ids.size() > 2)
|
||||
settings.component_ids.resize(2);
|
||||
if (settings.component_ids.size() < 2)
|
||||
return std::nullopt;
|
||||
if (!zone.is_linear_gradient())
|
||||
return std::nullopt;
|
||||
|
||||
settings.component_colors.reserve(settings.component_ids.size());
|
||||
settings.strength_factors.reserve(settings.component_ids.size());
|
||||
@@ -4380,12 +4364,14 @@ std::optional<SurfaceGradientPreviewSettings> surface_gradient_preview_settings_
|
||||
const ColorRGBA base_color = blend_component_colors(settings.component_colors, base_weights);
|
||||
settings.base_color = { base_color.r(), base_color.g(), base_color.b() };
|
||||
if (zone.is_linear_gradient()) {
|
||||
settings.linear_gradient_stops = TextureMappingManager::normalized_linear_gradient_stops(zone, num_physical);
|
||||
settings.linear_gradient_lut_colors.reserve(k_surface_gradient_preview_lut_size);
|
||||
for (size_t idx = 0; idx < k_surface_gradient_preview_lut_size; ++idx) {
|
||||
const float t = k_surface_gradient_preview_lut_size > 1 ?
|
||||
float(idx) / float(k_surface_gradient_preview_lut_size - 1) :
|
||||
0.f;
|
||||
const std::vector<float> weights = compact_linear_gradient_weights(t, settings.component_colors.size());
|
||||
const std::vector<float> weights =
|
||||
TextureMappingManager::linear_gradient_compact_weights(t, settings.linear_gradient_stops, settings.component_ids);
|
||||
const std::array<float, 3> rgb =
|
||||
mix_color_solver_components(settings.component_colors, weights, ColorSolverMixModel::PigmentPainter);
|
||||
settings.linear_gradient_lut_colors.push_back({ std::clamp(rgb[0], 0.f, 1.f),
|
||||
@@ -5228,6 +5214,10 @@ static void texture_preview_mix_zone_baked_model_settings(size_t &signature,
|
||||
};
|
||||
mix_anchor(zone.linear_gradient_start);
|
||||
mix_anchor(zone.linear_gradient_end);
|
||||
for (const TextureMappingZone::LinearGradientStop &stop : TextureMappingManager::normalized_linear_gradient_stops(zone, num_physical)) {
|
||||
signature_mix_float(stop.position, 10000.f);
|
||||
signature_mix(std::hash<unsigned int>{}(stop.filament_id));
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::string> physical_colors = physical_filament_colors_for_texture_preview(num_physical);
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
#include "libslic3r/Format/STL.hpp"
|
||||
#include "libslic3r/Format/DRC.hpp"
|
||||
#include "libslic3r/Format/STEP.hpp"
|
||||
#include "libslic3r/ColorSolver.hpp"
|
||||
#include "libslic3r/Format/AMF.hpp"
|
||||
//#include "libslic3r/Format/3mf.hpp"
|
||||
#include "libslic3r/Format/bbs_3mf.hpp"
|
||||
@@ -879,6 +880,8 @@ static std::vector<unsigned int> texture_mapping_selected_ids(const TextureMappi
|
||||
return id == 0 || id > num_physical || id > 9;
|
||||
}), ids.end());
|
||||
ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
|
||||
if (zone.is_linear_gradient())
|
||||
return ids;
|
||||
if (ids.size() < 2) {
|
||||
ids.clear();
|
||||
for (size_t i = 1; i <= std::min<size_t>(num_physical, 9); ++i)
|
||||
@@ -886,8 +889,6 @@ static std::vector<unsigned int> texture_mapping_selected_ids(const TextureMappi
|
||||
}
|
||||
if (ids.size() < 2 && num_physical >= 2)
|
||||
ids = {1, 2};
|
||||
if (zone.is_linear_gradient() && ids.size() > 2)
|
||||
ids.resize(2);
|
||||
return ids;
|
||||
}
|
||||
|
||||
@@ -1054,12 +1055,14 @@ public:
|
||||
void set_data(const std::vector<wxColour> &palette,
|
||||
const std::vector<unsigned int> &component_ids,
|
||||
const wxColour &fallback,
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &linear_gradient_stops = {},
|
||||
bool linear_gradient = false,
|
||||
bool radial_gradient = false)
|
||||
{
|
||||
m_palette = palette;
|
||||
m_component_ids = component_ids;
|
||||
m_fallback = fallback.IsOk() ? fallback : wxColour("#26A69A");
|
||||
m_linear_gradient_stops = linear_gradient_stops;
|
||||
m_linear_gradient = linear_gradient;
|
||||
m_radial_gradient = radial_gradient;
|
||||
Refresh();
|
||||
@@ -1073,6 +1076,24 @@ private:
|
||||
return m_fallback;
|
||||
}
|
||||
|
||||
wxColour gradient_color_for(double t) const
|
||||
{
|
||||
if (m_component_ids.empty())
|
||||
return m_fallback;
|
||||
std::vector<std::array<float, 3>> colors;
|
||||
colors.reserve(m_component_ids.size());
|
||||
for (const unsigned int id : m_component_ids) {
|
||||
const wxColour color = color_for(id);
|
||||
colors.push_back({float(color.Red()) / 255.f, float(color.Green()) / 255.f, float(color.Blue()) / 255.f});
|
||||
}
|
||||
const std::vector<float> weights =
|
||||
TextureMappingManager::linear_gradient_compact_weights(float(t), m_linear_gradient_stops, m_component_ids);
|
||||
const std::array<float, 3> mixed = mix_color_solver_components(colors, weights, ColorSolverMixModel::PigmentPainter);
|
||||
return wxColour(std::clamp(int(std::lround(mixed[0] * 255.f)), 0, 255),
|
||||
std::clamp(int(std::lround(mixed[1] * 255.f)), 0, 255),
|
||||
std::clamp(int(std::lround(mixed[2] * 255.f)), 0, 255));
|
||||
}
|
||||
|
||||
void on_paint(wxPaintEvent &)
|
||||
{
|
||||
wxAutoBufferedPaintDC dc(this);
|
||||
@@ -1084,12 +1105,7 @@ private:
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
dc.SetBrush(wxBrush(m_fallback));
|
||||
dc.DrawRectangle(rect);
|
||||
if (m_linear_gradient && m_component_ids.size() >= 2) {
|
||||
const wxColour start = color_for(m_component_ids[0]);
|
||||
const wxColour end = color_for(m_component_ids[1]);
|
||||
auto mix_channel = [](double t, unsigned char a, unsigned char b) {
|
||||
return static_cast<unsigned char>(std::lround(double(a) * (1.0 - t) + double(b) * t));
|
||||
};
|
||||
if (m_linear_gradient && !m_component_ids.empty()) {
|
||||
if (m_radial_gradient) {
|
||||
const double cx = double(rect.GetLeft()) + 0.5 * double(rect.GetWidth() - 1);
|
||||
const double cy = double(rect.GetTop()) + 0.5 * double(rect.GetHeight() - 1);
|
||||
@@ -1097,9 +1113,7 @@ private:
|
||||
for (int y = rect.GetTop(); y <= rect.GetBottom(); ++y) {
|
||||
for (int x = rect.GetLeft(); x <= rect.GetRight(); ++x) {
|
||||
const double t = std::clamp(std::hypot(double(x) - cx, double(y) - cy) / radius, 0.0, 1.0);
|
||||
dc.SetPen(wxPen(wxColour(mix_channel(t, start.Red(), end.Red()),
|
||||
mix_channel(t, start.Green(), end.Green()),
|
||||
mix_channel(t, start.Blue(), end.Blue()))));
|
||||
dc.SetPen(wxPen(gradient_color_for(t)));
|
||||
dc.DrawPoint(x, y);
|
||||
}
|
||||
}
|
||||
@@ -1108,9 +1122,7 @@ private:
|
||||
const int h = std::max(1, rect.GetHeight());
|
||||
for (int y = 0; y < h; ++y) {
|
||||
const double t = h <= 1 ? 0.0 : double(h - 1 - y) / double(h - 1);
|
||||
dc.SetBrush(wxBrush(wxColour(mix_channel(t, start.Red(), end.Red()),
|
||||
mix_channel(t, start.Green(), end.Green()),
|
||||
mix_channel(t, start.Blue(), end.Blue()))));
|
||||
dc.SetBrush(wxBrush(gradient_color_for(t)));
|
||||
dc.DrawRectangle(rect.GetLeft(), rect.GetTop() + y, rect.GetWidth(), 1);
|
||||
}
|
||||
}
|
||||
@@ -1128,11 +1140,331 @@ private:
|
||||
|
||||
std::vector<wxColour> m_palette;
|
||||
std::vector<unsigned int> m_component_ids;
|
||||
std::vector<TextureMappingZone::LinearGradientStop> m_linear_gradient_stops;
|
||||
wxColour m_fallback {wxColour("#26A69A")};
|
||||
bool m_linear_gradient { false };
|
||||
bool m_radial_gradient { false };
|
||||
};
|
||||
|
||||
class LinearGradientStopsBar : public wxPanel
|
||||
{
|
||||
public:
|
||||
explicit LinearGradientStopsBar(wxWindow *parent)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, from_dip_for_parent(parent, wxSize(320, 44)), wxBORDER_NONE)
|
||||
{
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
SetMinSize(wxSize(FromDIP(220), FromDIP(44)));
|
||||
Bind(wxEVT_PAINT, &LinearGradientStopsBar::on_paint, this);
|
||||
Bind(wxEVT_LEFT_DOWN, &LinearGradientStopsBar::on_left_down, this);
|
||||
Bind(wxEVT_LEFT_DCLICK, &LinearGradientStopsBar::on_left_dclick, this);
|
||||
Bind(wxEVT_LEFT_UP, &LinearGradientStopsBar::on_left_up, this);
|
||||
Bind(wxEVT_MOTION, &LinearGradientStopsBar::on_motion, this);
|
||||
}
|
||||
|
||||
void set_data(const std::vector<wxColour> &palette,
|
||||
size_t num_physical,
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &stops,
|
||||
int selected_index)
|
||||
{
|
||||
m_palette = palette;
|
||||
m_num_physical = num_physical;
|
||||
m_stops = stops;
|
||||
sort_stops();
|
||||
m_selected_index = selected_index >= 0 && selected_index < int(m_stops.size()) ? selected_index : -1;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> &stops() const { return m_stops; }
|
||||
int selected_index() const { return m_selected_index; }
|
||||
|
||||
void set_changed_callback(std::function<void(const std::vector<TextureMappingZone::LinearGradientStop> &, int)> callback)
|
||||
{
|
||||
m_changed_callback = std::move(callback);
|
||||
}
|
||||
|
||||
void set_selection_callback(std::function<void(int)> callback)
|
||||
{
|
||||
m_selection_callback = std::move(callback);
|
||||
}
|
||||
|
||||
void add_point_at_largest_gap()
|
||||
{
|
||||
if (m_stops.empty())
|
||||
return;
|
||||
sort_stops();
|
||||
float best_gap = std::clamp(m_stops.front().position, 0.f, 1.f);
|
||||
float best_position = 0.5f * best_gap;
|
||||
for (size_t i = 0; i + 1 < m_stops.size(); ++i) {
|
||||
const float gap = m_stops[i + 1].position - m_stops[i].position;
|
||||
if (gap > best_gap) {
|
||||
best_gap = gap;
|
||||
best_position = 0.5f * (m_stops[i].position + m_stops[i + 1].position);
|
||||
}
|
||||
}
|
||||
const float tail_gap = std::clamp(1.f - m_stops.back().position, 0.f, 1.f);
|
||||
if (tail_gap > best_gap)
|
||||
best_position = 0.5f * (m_stops.back().position + 1.f);
|
||||
add_stop(best_position);
|
||||
}
|
||||
|
||||
void remove_selected()
|
||||
{
|
||||
if (m_selected_index < 0 || m_selected_index >= int(m_stops.size()) || m_stops.size() <= 2)
|
||||
return;
|
||||
m_stops.erase(m_stops.begin() + m_selected_index);
|
||||
m_selected_index = -1;
|
||||
notify_changed();
|
||||
notify_selection();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void set_selected_filament(unsigned int filament_id)
|
||||
{
|
||||
if (m_selected_index < 0 || m_selected_index >= int(m_stops.size()) || filament_id == 0)
|
||||
return;
|
||||
m_stops[size_t(m_selected_index)].filament_id = normalize_filament_id(filament_id);
|
||||
notify_changed();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void set_edge_filament(bool start_edge, unsigned int filament_id)
|
||||
{
|
||||
if (m_stops.empty() || filament_id == 0)
|
||||
return;
|
||||
sort_stops();
|
||||
m_stops[start_edge ? 0 : m_stops.size() - 1].filament_id = normalize_filament_id(filament_id);
|
||||
notify_changed();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int max_filament_id() const
|
||||
{
|
||||
return unsigned(std::min<size_t>(m_num_physical, 9));
|
||||
}
|
||||
|
||||
unsigned int normalize_filament_id(unsigned int filament_id) const
|
||||
{
|
||||
const unsigned int max_id = max_filament_id();
|
||||
return max_id == 0 ? 0u : std::clamp(filament_id, 1u, max_id);
|
||||
}
|
||||
|
||||
wxColour color_for(unsigned int id) const
|
||||
{
|
||||
if (id >= 1 && id <= m_palette.size())
|
||||
return m_palette[id - 1];
|
||||
return wxColour("#808080");
|
||||
}
|
||||
|
||||
wxColour gradient_color_for(float t) const
|
||||
{
|
||||
std::vector<unsigned int> component_ids;
|
||||
bool seen[10] = { false };
|
||||
for (const TextureMappingZone::LinearGradientStop &stop : m_stops) {
|
||||
const unsigned int id = stop.filament_id;
|
||||
if (id == 0 || id > m_num_physical || id > 9 || seen[id])
|
||||
continue;
|
||||
seen[id] = true;
|
||||
component_ids.emplace_back(id);
|
||||
}
|
||||
if (component_ids.empty())
|
||||
return wxColour("#808080");
|
||||
std::vector<std::array<float, 3>> colors;
|
||||
colors.reserve(component_ids.size());
|
||||
for (const unsigned int id : component_ids) {
|
||||
const wxColour color = color_for(id);
|
||||
colors.push_back({float(color.Red()) / 255.f, float(color.Green()) / 255.f, float(color.Blue()) / 255.f});
|
||||
}
|
||||
const std::vector<float> weights = TextureMappingManager::linear_gradient_compact_weights(t, m_stops, component_ids);
|
||||
const std::array<float, 3> mixed = mix_color_solver_components(colors, weights, ColorSolverMixModel::PigmentPainter);
|
||||
return wxColour(std::clamp(int(std::lround(mixed[0] * 255.f)), 0, 255),
|
||||
std::clamp(int(std::lround(mixed[1] * 255.f)), 0, 255),
|
||||
std::clamp(int(std::lround(mixed[2] * 255.f)), 0, 255));
|
||||
}
|
||||
|
||||
wxRect bar_rect() const
|
||||
{
|
||||
const wxSize size = GetClientSize();
|
||||
const int handle_radius = FromDIP(7);
|
||||
const int left = handle_radius + FromDIP(2);
|
||||
const int right = std::max(left + 1, size.x - handle_radius - FromDIP(2));
|
||||
const int height = FromDIP(14);
|
||||
const int top = std::max(FromDIP(4), (size.y - height) / 2);
|
||||
return wxRect(left, top, right - left, height);
|
||||
}
|
||||
|
||||
int x_for_position(float position) const
|
||||
{
|
||||
const wxRect rect = bar_rect();
|
||||
return rect.GetLeft() + int(std::lround(std::clamp(position, 0.f, 1.f) * float(rect.GetWidth())));
|
||||
}
|
||||
|
||||
float position_for_x(int x) const
|
||||
{
|
||||
const wxRect rect = bar_rect();
|
||||
if (rect.GetWidth() <= 0)
|
||||
return 0.f;
|
||||
return std::clamp(float(x - rect.GetLeft()) / float(rect.GetWidth()), 0.f, 1.f);
|
||||
}
|
||||
|
||||
int hit_stop(const wxPoint &point) const
|
||||
{
|
||||
const wxRect rect = bar_rect();
|
||||
const int cy = rect.GetTop() + rect.GetHeight() / 2;
|
||||
const int radius = FromDIP(9);
|
||||
int best_idx = -1;
|
||||
int best_dist_sq = radius * radius + 1;
|
||||
for (size_t i = 0; i < m_stops.size(); ++i) {
|
||||
const int dx = point.x - x_for_position(m_stops[i].position);
|
||||
const int dy = point.y - cy;
|
||||
const int dist_sq = dx * dx + dy * dy;
|
||||
if (dist_sq <= radius * radius && dist_sq < best_dist_sq) {
|
||||
best_idx = int(i);
|
||||
best_dist_sq = dist_sq;
|
||||
}
|
||||
}
|
||||
return best_idx;
|
||||
}
|
||||
|
||||
void sort_stops()
|
||||
{
|
||||
std::stable_sort(m_stops.begin(), m_stops.end(), [](const auto &lhs, const auto &rhs) {
|
||||
return lhs.position < rhs.position;
|
||||
});
|
||||
}
|
||||
|
||||
unsigned int filament_for_new_stop(float position) const
|
||||
{
|
||||
if (m_stops.empty())
|
||||
return normalize_filament_id(1);
|
||||
size_t best_idx = 0;
|
||||
float best_distance = std::numeric_limits<float>::max();
|
||||
for (size_t i = 0; i < m_stops.size(); ++i) {
|
||||
const float distance = std::abs(m_stops[i].position - position);
|
||||
if (distance < best_distance) {
|
||||
best_idx = i;
|
||||
best_distance = distance;
|
||||
}
|
||||
}
|
||||
return normalize_filament_id(m_stops[best_idx].filament_id);
|
||||
}
|
||||
|
||||
void add_stop(float position)
|
||||
{
|
||||
TextureMappingZone::LinearGradientStop stop;
|
||||
stop.position = std::clamp(position, 0.f, 1.f);
|
||||
stop.filament_id = filament_for_new_stop(stop.position);
|
||||
sort_stops();
|
||||
auto insert_it = std::upper_bound(m_stops.begin(), m_stops.end(), stop.position, [](float value, const auto &rhs) {
|
||||
return value < rhs.position;
|
||||
});
|
||||
m_selected_index = int(insert_it - m_stops.begin());
|
||||
m_stops.insert(insert_it, stop);
|
||||
notify_changed();
|
||||
notify_selection();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void set_stop_position(int index, float position)
|
||||
{
|
||||
if (index < 0 || index >= int(m_stops.size()))
|
||||
return;
|
||||
TextureMappingZone::LinearGradientStop stop = m_stops[size_t(index)];
|
||||
stop.position = std::clamp(position, 0.f, 1.f);
|
||||
m_stops.erase(m_stops.begin() + index);
|
||||
auto insert_it = std::upper_bound(m_stops.begin(), m_stops.end(), stop.position, [](float value, const auto &rhs) {
|
||||
return value < rhs.position;
|
||||
});
|
||||
m_selected_index = int(insert_it - m_stops.begin());
|
||||
m_stops.insert(insert_it, stop);
|
||||
notify_changed();
|
||||
notify_selection();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void notify_changed()
|
||||
{
|
||||
if (m_changed_callback)
|
||||
m_changed_callback(m_stops, m_selected_index);
|
||||
}
|
||||
|
||||
void notify_selection()
|
||||
{
|
||||
if (m_selection_callback)
|
||||
m_selection_callback(m_selected_index);
|
||||
}
|
||||
|
||||
void on_paint(wxPaintEvent &)
|
||||
{
|
||||
wxAutoBufferedPaintDC dc(this);
|
||||
dc.SetBackground(wxBrush(GetBackgroundColour()));
|
||||
dc.Clear();
|
||||
const wxRect rect = bar_rect();
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
for (int x = rect.GetLeft(); x <= rect.GetRight(); ++x) {
|
||||
const float t = position_for_x(x);
|
||||
dc.SetBrush(wxBrush(gradient_color_for(t)));
|
||||
dc.DrawRectangle(x, rect.GetTop(), 1, rect.GetHeight());
|
||||
}
|
||||
dc.SetPen(wxPen(wxColour(90, 90, 90), FromDIP(1)));
|
||||
dc.SetBrush(*wxTRANSPARENT_BRUSH);
|
||||
dc.DrawRoundedRectangle(rect, FromDIP(3));
|
||||
|
||||
const int cy = rect.GetTop() + rect.GetHeight() / 2;
|
||||
const int radius = FromDIP(7);
|
||||
for (size_t i = 0; i < m_stops.size(); ++i) {
|
||||
const int x = x_for_position(m_stops[i].position);
|
||||
dc.SetBrush(wxBrush(color_for(m_stops[i].filament_id)));
|
||||
dc.SetPen(wxPen(i == size_t(m_selected_index) ? wxColour(255, 255, 255) : wxColour(30, 30, 30),
|
||||
i == size_t(m_selected_index) ? FromDIP(3) : FromDIP(2)));
|
||||
dc.DrawCircle(wxPoint(x, cy), radius);
|
||||
}
|
||||
}
|
||||
|
||||
void on_left_down(wxMouseEvent &evt)
|
||||
{
|
||||
const int hit = hit_stop(evt.GetPosition());
|
||||
if (hit >= 0) {
|
||||
m_selected_index = hit;
|
||||
m_dragging = true;
|
||||
if (!HasCapture())
|
||||
CaptureMouse();
|
||||
} else {
|
||||
m_selected_index = -1;
|
||||
}
|
||||
notify_selection();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void on_left_dclick(wxMouseEvent &evt)
|
||||
{
|
||||
if (hit_stop(evt.GetPosition()) < 0)
|
||||
add_stop(position_for_x(evt.GetX()));
|
||||
}
|
||||
|
||||
void on_left_up(wxMouseEvent &)
|
||||
{
|
||||
m_dragging = false;
|
||||
if (HasCapture())
|
||||
ReleaseMouse();
|
||||
}
|
||||
|
||||
void on_motion(wxMouseEvent &evt)
|
||||
{
|
||||
if (!m_dragging || m_selected_index < 0 || !evt.Dragging() || !evt.LeftIsDown())
|
||||
return;
|
||||
set_stop_position(m_selected_index, position_for_x(evt.GetX()));
|
||||
}
|
||||
|
||||
std::vector<wxColour> m_palette;
|
||||
size_t m_num_physical { 0 };
|
||||
std::vector<TextureMappingZone::LinearGradientStop> m_stops;
|
||||
int m_selected_index { -1 };
|
||||
bool m_dragging { false };
|
||||
std::function<void(const std::vector<TextureMappingZone::LinearGradientStop> &, int)> m_changed_callback;
|
||||
std::function<void(int)> m_selection_callback;
|
||||
};
|
||||
|
||||
class TextureMappingNumberSwatch : public wxPanel
|
||||
{
|
||||
public:
|
||||
@@ -4549,13 +4881,15 @@ Sidebar::Sidebar(Plater *parent)
|
||||
return;
|
||||
ConfigOptionStrings *colors_opt = bundle->project_config.option<ConfigOptionStrings>("filament_colour");
|
||||
std::vector<std::string> colors = colors_opt ? colors_opt->values : std::vector<std::string>();
|
||||
if (colors.size() < 2)
|
||||
if (colors.empty())
|
||||
return;
|
||||
const std::string serialized = bundle->project_config.has("texture_mapping_definitions") ?
|
||||
bundle->project_config.opt_string("texture_mapping_definitions") :
|
||||
std::string();
|
||||
bundle->texture_mapping_zones.load_entries(serialized, colors);
|
||||
bundle->texture_mapping_zones.add_zone(colors.size(), colors);
|
||||
bundle->texture_mapping_zones.add_zone(colors.size(),
|
||||
colors,
|
||||
colors.size() < 2 ? int(TextureMappingZone::LinearGradient) : int(TextureMappingZone::ImageTexture));
|
||||
persist_texture_mapping();
|
||||
};
|
||||
|
||||
@@ -6295,9 +6629,9 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
};
|
||||
|
||||
if (p->m_btn_add_texture_map != nullptr)
|
||||
p->m_btn_add_texture_map->Enable(num_physical >= 2);
|
||||
p->m_btn_add_texture_map->Enable(num_physical >= 1);
|
||||
|
||||
if (num_physical < 2) {
|
||||
if (num_physical == 0) {
|
||||
p->m_panel_texture_mapping_title->Hide();
|
||||
p->m_panel_texture_mapping_content->Hide();
|
||||
if (p->m_panel_texture_mapping_resize_handle != nullptr)
|
||||
@@ -6357,49 +6691,6 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
combo->SetSelection(std::clamp(int(id) - 1, 0, int(combo->GetCount() - 1)));
|
||||
};
|
||||
|
||||
auto linear_gradient_filament_ids = [num_physical, filament_combo_id, set_filament_combo_id](::ComboBox *start_combo,
|
||||
::ComboBox *end_combo,
|
||||
const TextureMappingZone &zone,
|
||||
int changed_side) {
|
||||
const unsigned int count = unsigned(std::min<size_t>(num_physical, 9));
|
||||
std::vector<unsigned int> ids;
|
||||
if (count == 0)
|
||||
return ids;
|
||||
auto normalize_id = [count](unsigned int id) {
|
||||
return id >= 1 && id <= count ? id : 1u;
|
||||
};
|
||||
unsigned int start_id = normalize_id(filament_combo_id(start_combo, zone.component_a));
|
||||
unsigned int end_id = normalize_id(filament_combo_id(end_combo, zone.component_b));
|
||||
auto different_id = [count](unsigned int id) {
|
||||
for (unsigned int candidate = 1; candidate <= count; ++candidate)
|
||||
if (candidate != id)
|
||||
return candidate;
|
||||
return id;
|
||||
};
|
||||
if (count == 1) {
|
||||
start_id = 1;
|
||||
end_id = 1;
|
||||
} else if (start_id == end_id) {
|
||||
if (changed_side == 1) {
|
||||
end_id = normalize_id(zone.component_a);
|
||||
if (end_id == start_id)
|
||||
end_id = different_id(start_id);
|
||||
} else if (changed_side == 2) {
|
||||
start_id = normalize_id(zone.component_b);
|
||||
if (start_id == end_id)
|
||||
start_id = different_id(end_id);
|
||||
} else {
|
||||
end_id = normalize_id(zone.component_b);
|
||||
if (end_id == start_id)
|
||||
end_id = different_id(start_id);
|
||||
}
|
||||
}
|
||||
set_filament_combo_id(start_combo, start_id);
|
||||
set_filament_combo_id(end_combo, end_id);
|
||||
ids = {start_id, end_id};
|
||||
return ids;
|
||||
};
|
||||
|
||||
auto repaint_sidebar_checkbox = [](::CheckBox *checkbox) {
|
||||
if (checkbox == nullptr)
|
||||
return;
|
||||
@@ -6569,6 +6860,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
TextureMappingManager::effective_texture_component_ids(entry, num_physical, physical_colors) :
|
||||
texture_mapping_selected_ids(entry, num_physical),
|
||||
parse_texture_mapping_color(entry.display_color),
|
||||
entry.is_linear_gradient() ? TextureMappingManager::normalized_linear_gradient_stops(entry, num_physical) : std::vector<TextureMappingZone::LinearGradientStop>(),
|
||||
entry.is_linear_gradient(),
|
||||
entry.is_radial_linear_gradient());
|
||||
header_sizer->Add(preview, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
@@ -6592,6 +6884,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
TextureMappingManager::effective_texture_component_ids(zone, num_physical, physical_colors) :
|
||||
texture_mapping_selected_ids(zone, num_physical),
|
||||
parse_texture_mapping_color(zone.display_color),
|
||||
zone.is_linear_gradient() ? TextureMappingManager::normalized_linear_gradient_stops(zone, num_physical) : std::vector<TextureMappingZone::LinearGradientStop>(),
|
||||
zone.is_linear_gradient(),
|
||||
zone.is_radial_linear_gradient());
|
||||
}
|
||||
@@ -6665,15 +6958,29 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
linear_gradient_mode_row->Add(linear_gradient_mode_choice, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
editor_sizer->Add(linear_gradient_mode_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
|
||||
std::vector<TextureMappingZone::LinearGradientStop> initial_linear_gradient_stops =
|
||||
TextureMappingManager::normalized_linear_gradient_stops(entry, num_physical);
|
||||
const unsigned int initial_start_filament = initial_linear_gradient_stops.empty() ? 1 : initial_linear_gradient_stops.front().filament_id;
|
||||
const unsigned int initial_end_filament = initial_linear_gradient_stops.empty() ? initial_start_filament : initial_linear_gradient_stops.back().filament_id;
|
||||
auto *linear_gradient_stops_bar = new LinearGradientStopsBar(editor);
|
||||
linear_gradient_stops_bar->SetBackgroundColour(row_bg);
|
||||
linear_gradient_stops_bar->set_data(palette, num_physical, initial_linear_gradient_stops, -1);
|
||||
editor_sizer->Add(linear_gradient_stops_bar, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
|
||||
auto *linear_gradient_row = new wxBoxSizer(wxHORIZONTAL);
|
||||
linear_gradient_row->Add(new wxStaticText(editor, wxID_ANY, _L("Gradient")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
auto *start_filament_combo = make_filament_swatch_combo(editor, selected_ids.empty() ? 1 : selected_ids.front());
|
||||
auto *end_filament_combo = make_filament_swatch_combo(editor, selected_ids.size() > 1 ? selected_ids[1] : (selected_ids.empty() ? 1 : selected_ids.front()));
|
||||
auto *start_filament_combo = make_filament_swatch_combo(editor, initial_start_filament);
|
||||
auto *end_filament_combo = make_filament_swatch_combo(editor, initial_end_filament);
|
||||
auto *point_filament_combo = make_filament_swatch_combo(editor, initial_start_filament);
|
||||
const bool can_choose_linear_gradient_filaments = std::min<size_t>(num_physical, 9) > 1;
|
||||
if (start_filament_combo != nullptr)
|
||||
start_filament_combo->Enable(can_choose_linear_gradient_filaments);
|
||||
if (end_filament_combo != nullptr)
|
||||
end_filament_combo->Enable(can_choose_linear_gradient_filaments);
|
||||
if (point_filament_combo != nullptr)
|
||||
point_filament_combo->Enable(can_choose_linear_gradient_filaments);
|
||||
auto *add_point_btn = new wxButton(editor, wxID_ANY, _L("Add Point"));
|
||||
auto *add_selected_point_btn = new wxButton(editor, wxID_ANY, _L("Add Point"));
|
||||
auto *remove_point_btn = new wxButton(editor, wxID_ANY, _L("Remove Point"));
|
||||
const bool entry_radial_gradient = linear_gradient_mode_selection(entry) == 1;
|
||||
auto *set_start_btn = new wxButton(editor,
|
||||
wxID_ANY,
|
||||
@@ -6688,8 +6995,16 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
linear_gradient_row->Add(start_filament_combo, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
linear_gradient_row->Add(new wxStaticText(editor, wxID_ANY, _L("End")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2);
|
||||
linear_gradient_row->Add(end_filament_combo, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
linear_gradient_row->Add(add_point_btn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
editor_sizer->Add(linear_gradient_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
|
||||
auto *linear_gradient_point_row = new wxBoxSizer(wxHORIZONTAL);
|
||||
linear_gradient_point_row->Add(new wxStaticText(editor, wxID_ANY, _L("Point")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap / 2);
|
||||
linear_gradient_point_row->Add(point_filament_combo, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
linear_gradient_point_row->Add(remove_point_btn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
linear_gradient_point_row->Add(add_selected_point_btn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
editor_sizer->Add(linear_gradient_point_row, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, gap);
|
||||
|
||||
auto *linear_gradient_buttons_row = new wxWrapSizer(wxHORIZONTAL, wxWRAPSIZER_DEFAULT_FLAGS);
|
||||
linear_gradient_buttons_row->Add(set_start_btn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
linear_gradient_buttons_row->Add(set_end_btn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
@@ -6774,6 +7089,41 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
Layout();
|
||||
};
|
||||
|
||||
auto sync_linear_gradient_stop_controls = [this,
|
||||
editor_sizer,
|
||||
linear_gradient_stops_bar,
|
||||
linear_gradient_row,
|
||||
linear_gradient_point_row,
|
||||
start_filament_combo,
|
||||
end_filament_combo,
|
||||
point_filament_combo,
|
||||
remove_point_btn,
|
||||
surface_choice,
|
||||
set_filament_combo_id,
|
||||
editor,
|
||||
row,
|
||||
update_texture_mapping_area_height]() {
|
||||
const bool linear_gradient = surface_choice != nullptr && surface_choice->GetSelection() == 1;
|
||||
const int selected_index = linear_gradient_stops_bar != nullptr ? linear_gradient_stops_bar->selected_index() : -1;
|
||||
const std::vector<TextureMappingZone::LinearGradientStop> stops =
|
||||
linear_gradient_stops_bar != nullptr ? linear_gradient_stops_bar->stops() : std::vector<TextureMappingZone::LinearGradientStop>();
|
||||
if (selected_index >= 0 && selected_index < int(stops.size())) {
|
||||
set_filament_combo_id(point_filament_combo, stops[size_t(selected_index)].filament_id);
|
||||
} else if (!stops.empty()) {
|
||||
set_filament_combo_id(start_filament_combo, stops.front().filament_id);
|
||||
set_filament_combo_id(end_filament_combo, stops.back().filament_id);
|
||||
}
|
||||
if (remove_point_btn != nullptr)
|
||||
remove_point_btn->Enable(stops.size() > 2);
|
||||
editor_sizer->Show(linear_gradient_row, linear_gradient && selected_index < 0, true);
|
||||
editor_sizer->Show(linear_gradient_point_row, linear_gradient && selected_index >= 0, true);
|
||||
editor->Layout();
|
||||
row->Layout();
|
||||
update_texture_mapping_area_height();
|
||||
m_scrolled_sizer->Layout();
|
||||
Layout();
|
||||
};
|
||||
|
||||
auto *mode_row = new wxWrapSizer(wxHORIZONTAL, wxWRAPSIZER_DEFAULT_FLAGS);
|
||||
mode_row->Add(new wxStaticText(editor, wxID_ANY, _L("Filament colors")), 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, gap);
|
||||
auto *mode_choice = make_sidebar_combo(editor,
|
||||
@@ -6812,10 +7162,10 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
editor_sizer->Add(button_row, 0, wxEXPAND | wxALL, gap);
|
||||
|
||||
auto apply_controls = [zone_index, mgr_ptr, num_physical, filament_checks, surface_choice,
|
||||
start_filament_combo, end_filament_combo, linear_gradient_mode_choice, linear_gradient_radius_spin,
|
||||
linear_gradient_stops_bar, linear_gradient_mode_choice, linear_gradient_radius_spin,
|
||||
linear_gradient_radius_percent_chk,
|
||||
linear_gradient_filament_ids, surface_pattern_from_selection, linear_gradient_mode_from_selection, mode_choice, preview_colors_chk,
|
||||
show_direction_arrow_chk, contrast_spin, apply_zone](int changed_side = 0) {
|
||||
surface_pattern_from_selection, linear_gradient_mode_from_selection, mode_choice, preview_colors_chk,
|
||||
show_direction_arrow_chk, contrast_spin, apply_zone]() {
|
||||
if (mgr_ptr == nullptr)
|
||||
return;
|
||||
auto &rows = mgr_ptr->zones();
|
||||
@@ -6825,7 +7175,11 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
const int surface_pattern = surface_pattern_from_selection(surface_choice != nullptr ? surface_choice->GetSelection() : 0);
|
||||
std::vector<unsigned int> ids;
|
||||
if (surface_pattern == int(TextureMappingZone::LinearGradient)) {
|
||||
ids = linear_gradient_filament_ids(start_filament_combo, end_filament_combo, updated, changed_side);
|
||||
updated.linear_gradient_stops = linear_gradient_stops_bar != nullptr ?
|
||||
linear_gradient_stops_bar->stops() :
|
||||
TextureMappingManager::normalized_linear_gradient_stops(updated, num_physical);
|
||||
updated.linear_gradient_stops = TextureMappingManager::normalized_linear_gradient_stops(updated, num_physical);
|
||||
ids = TextureMappingManager::linear_gradient_component_ids_from_stops(updated, num_physical);
|
||||
} else {
|
||||
for (size_t idx = 0; idx < filament_checks.size(); ++idx)
|
||||
if (filament_checks[idx] != nullptr && filament_checks[idx]->GetValue())
|
||||
@@ -6836,8 +7190,13 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.enabled = true;
|
||||
updated.surface_pattern = surface_pattern;
|
||||
updated.component_ids = encode_texture_mapping_component_ids(ids);
|
||||
updated.component_a = ids.empty() ? 1 : ids.front();
|
||||
updated.component_b = ids.size() > 1 ? ids[1] : updated.component_a;
|
||||
if (updated.is_linear_gradient() && !updated.linear_gradient_stops.empty()) {
|
||||
updated.component_a = updated.linear_gradient_stops.front().filament_id;
|
||||
updated.component_b = updated.linear_gradient_stops.back().filament_id;
|
||||
} else {
|
||||
updated.component_a = ids.empty() ? 1 : ids.front();
|
||||
updated.component_b = ids.size() > 1 ? ids[1] : updated.component_a;
|
||||
}
|
||||
updated.linear_gradient_mode = linear_gradient_mode_from_selection(linear_gradient_mode_choice != nullptr ?
|
||||
linear_gradient_mode_choice->GetSelection() :
|
||||
0);
|
||||
@@ -6862,6 +7221,16 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
apply_zone(std::move(updated));
|
||||
};
|
||||
|
||||
if (linear_gradient_stops_bar != nullptr) {
|
||||
linear_gradient_stops_bar->set_changed_callback([apply_controls, sync_linear_gradient_stop_controls](const std::vector<TextureMappingZone::LinearGradientStop> &, int) {
|
||||
sync_linear_gradient_stop_controls();
|
||||
apply_controls();
|
||||
});
|
||||
linear_gradient_stops_bar->set_selection_callback([sync_linear_gradient_stop_controls](int) {
|
||||
sync_linear_gradient_stop_controls();
|
||||
});
|
||||
}
|
||||
|
||||
contrast_spin->Bind(wxEVT_CHAR_HOOK, [contrast_spin, apply_controls](wxKeyEvent &evt) {
|
||||
const int key = evt.GetKeyCode();
|
||||
if (key == WXK_UP || key == WXK_NUMPAD_UP || key == WXK_DOWN || key == WXK_NUMPAD_DOWN) {
|
||||
@@ -6872,14 +7241,17 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
}
|
||||
evt.Skip();
|
||||
});
|
||||
auto update_pattern_visibility = [this, editor_sizer, filaments_row, linear_gradient_mode_row, linear_gradient_mode_choice, linear_gradient_row, linear_gradient_buttons_row, linear_gradient_radius_row, show_direction_arrow_row, mode_row, contrast_row, preview_colors_row, offset_btn, advanced_btn, surface_choice, row, editor, update_texture_mapping_area_height, set_linear_gradient_picker_button_labels]() {
|
||||
auto update_pattern_visibility = [this, editor_sizer, filaments_row, linear_gradient_mode_row, linear_gradient_mode_choice, linear_gradient_stops_bar, linear_gradient_row, linear_gradient_point_row, linear_gradient_buttons_row, linear_gradient_radius_row, show_direction_arrow_row, mode_row, contrast_row, preview_colors_row, offset_btn, advanced_btn, surface_choice, row, editor, update_texture_mapping_area_height, set_linear_gradient_picker_button_labels, sync_linear_gradient_stop_controls]() {
|
||||
const int selection = surface_choice == nullptr ? 0 : surface_choice->GetSelection();
|
||||
const bool image_texture = selection == 0;
|
||||
const bool linear_gradient = selection == 1;
|
||||
const bool radial_gradient = linear_gradient && linear_gradient_mode_choice != nullptr && linear_gradient_mode_choice->GetSelection() == 1;
|
||||
const int selected_stop = linear_gradient_stops_bar != nullptr ? linear_gradient_stops_bar->selected_index() : -1;
|
||||
editor_sizer->Show(filaments_row, !linear_gradient, true);
|
||||
editor_sizer->Show(linear_gradient_mode_row, linear_gradient, true);
|
||||
editor_sizer->Show(linear_gradient_row, linear_gradient, true);
|
||||
editor_sizer->Show(linear_gradient_stops_bar, linear_gradient, true);
|
||||
editor_sizer->Show(linear_gradient_row, linear_gradient && selected_stop < 0, true);
|
||||
editor_sizer->Show(linear_gradient_point_row, linear_gradient && selected_stop >= 0, true);
|
||||
editor_sizer->Show(linear_gradient_buttons_row, linear_gradient, true);
|
||||
editor_sizer->Show(linear_gradient_radius_row, radial_gradient, true);
|
||||
editor_sizer->Show(show_direction_arrow_row, linear_gradient, true);
|
||||
@@ -6891,6 +7263,7 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
if (advanced_btn != nullptr)
|
||||
advanced_btn->Show();
|
||||
set_linear_gradient_picker_button_labels(GLGizmoTextureGradientPointPicker::Target::None);
|
||||
sync_linear_gradient_stop_controls();
|
||||
editor->Layout();
|
||||
row->Layout();
|
||||
update_texture_mapping_area_height();
|
||||
@@ -6915,9 +7288,33 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
evt.Skip();
|
||||
});
|
||||
if (start_filament_combo != nullptr)
|
||||
start_filament_combo->Bind(wxEVT_COMBOBOX, [apply_controls](wxCommandEvent &) { apply_controls(1); });
|
||||
start_filament_combo->Bind(wxEVT_COMBOBOX, [linear_gradient_stops_bar, start_filament_combo, filament_combo_id](wxCommandEvent &) {
|
||||
if (linear_gradient_stops_bar != nullptr)
|
||||
linear_gradient_stops_bar->set_edge_filament(true, filament_combo_id(start_filament_combo, 1));
|
||||
});
|
||||
if (end_filament_combo != nullptr)
|
||||
end_filament_combo->Bind(wxEVT_COMBOBOX, [apply_controls](wxCommandEvent &) { apply_controls(2); });
|
||||
end_filament_combo->Bind(wxEVT_COMBOBOX, [linear_gradient_stops_bar, end_filament_combo, filament_combo_id](wxCommandEvent &) {
|
||||
if (linear_gradient_stops_bar != nullptr)
|
||||
linear_gradient_stops_bar->set_edge_filament(false, filament_combo_id(end_filament_combo, 1));
|
||||
});
|
||||
if (point_filament_combo != nullptr)
|
||||
point_filament_combo->Bind(wxEVT_COMBOBOX, [linear_gradient_stops_bar, point_filament_combo, filament_combo_id](wxCommandEvent &) {
|
||||
if (linear_gradient_stops_bar != nullptr)
|
||||
linear_gradient_stops_bar->set_selected_filament(filament_combo_id(point_filament_combo, 1));
|
||||
});
|
||||
auto add_linear_gradient_point = [linear_gradient_stops_bar](wxCommandEvent &) {
|
||||
if (linear_gradient_stops_bar != nullptr)
|
||||
linear_gradient_stops_bar->add_point_at_largest_gap();
|
||||
};
|
||||
if (add_point_btn != nullptr)
|
||||
add_point_btn->Bind(wxEVT_BUTTON, add_linear_gradient_point);
|
||||
if (add_selected_point_btn != nullptr)
|
||||
add_selected_point_btn->Bind(wxEVT_BUTTON, add_linear_gradient_point);
|
||||
if (remove_point_btn != nullptr)
|
||||
remove_point_btn->Bind(wxEVT_BUTTON, [linear_gradient_stops_bar](wxCommandEvent &) {
|
||||
if (linear_gradient_stops_bar != nullptr)
|
||||
linear_gradient_stops_bar->remove_selected();
|
||||
});
|
||||
int last_mode_selection = mode_choice->GetSelection();
|
||||
auto on_mode_choice = [this,
|
||||
zone_index,
|
||||
@@ -6925,12 +7322,10 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
num_physical,
|
||||
physical_colors,
|
||||
filament_checks,
|
||||
start_filament_combo,
|
||||
end_filament_combo,
|
||||
linear_gradient_stops_bar,
|
||||
linear_gradient_mode_choice,
|
||||
linear_gradient_radius_spin,
|
||||
linear_gradient_radius_percent_chk,
|
||||
linear_gradient_filament_ids,
|
||||
linear_gradient_mode_from_selection,
|
||||
mode_choice,
|
||||
surface_choice,
|
||||
@@ -6955,7 +7350,11 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
const int surface_pattern = surface_pattern_from_selection(surface_choice != nullptr ? surface_choice->GetSelection() : 0);
|
||||
std::vector<unsigned int> ids;
|
||||
if (surface_pattern == int(TextureMappingZone::LinearGradient)) {
|
||||
ids = linear_gradient_filament_ids(start_filament_combo, end_filament_combo, updated, 0);
|
||||
updated.linear_gradient_stops = linear_gradient_stops_bar != nullptr ?
|
||||
linear_gradient_stops_bar->stops() :
|
||||
TextureMappingManager::normalized_linear_gradient_stops(updated, num_physical);
|
||||
updated.linear_gradient_stops = TextureMappingManager::normalized_linear_gradient_stops(updated, num_physical);
|
||||
ids = TextureMappingManager::linear_gradient_component_ids_from_stops(updated, num_physical);
|
||||
} else {
|
||||
for (size_t idx = 0; idx < filament_checks.size(); ++idx)
|
||||
if (filament_checks[idx] != nullptr && filament_checks[idx]->GetValue())
|
||||
@@ -6967,8 +7366,13 @@ void Sidebar::update_texture_mapping_panel(bool sync_manager)
|
||||
updated.enabled = true;
|
||||
updated.surface_pattern = surface_pattern;
|
||||
updated.component_ids = encode_texture_mapping_component_ids(ids);
|
||||
updated.component_a = ids.empty() ? 1 : ids.front();
|
||||
updated.component_b = ids.size() > 1 ? ids[1] : updated.component_a;
|
||||
if (updated.is_linear_gradient() && !updated.linear_gradient_stops.empty()) {
|
||||
updated.component_a = updated.linear_gradient_stops.front().filament_id;
|
||||
updated.component_b = updated.linear_gradient_stops.back().filament_id;
|
||||
} else {
|
||||
updated.component_a = ids.empty() ? 1 : ids.front();
|
||||
updated.component_b = ids.size() > 1 ? ids[1] : updated.component_a;
|
||||
}
|
||||
updated.linear_gradient_mode = linear_gradient_mode_from_selection(linear_gradient_mode_choice != nullptr ?
|
||||
linear_gradient_mode_choice->GetSelection() :
|
||||
0);
|
||||
|
||||
Reference in New Issue
Block a user